Browse Source

Merge branch 'V20220125' into zouap_user

tags/v1.22.1.3
zouap 3 years ago
parent
commit
efc3ee1203
23 changed files with 1956 additions and 104 deletions
  1. BIN
      custom/public/img/ranking_list.jpg
  2. +98
    -25
      models/cloudbrain.go
  3. +13
    -8
      modules/auth/cloudbrain.go
  4. +40
    -32
      modules/cloudbrain/cloudbrain.go
  5. +101
    -0
      modules/cloudbrain/resty.go
  6. +13
    -5
      modules/setting/setting.go
  7. +8
    -0
      options/locale/locale_en-US.ini
  8. +8
    -0
      options/locale/locale_zh-CN.ini
  9. +1
    -0
      routers/api/v1/api.go
  10. +57
    -0
      routers/api/v1/repo/cloudbrain.go
  11. +2
    -1
      routers/api/v1/repo/modelarts.go
  12. +416
    -16
      routers/repo/cloudbrain.go
  13. +10
    -10
      routers/repo/modelarts.go
  14. +13
    -0
      routers/routes/routes.go
  15. +387
    -0
      templates/repo/cloudbrain/benchmark/index.tmpl
  16. +243
    -0
      templates/repo/cloudbrain/benchmark/new.tmpl
  17. +437
    -0
      templates/repo/cloudbrain/benchmark/show.tmpl
  18. +1
    -4
      templates/repo/cloudbrain/new.tmpl
  19. +1
    -0
      templates/repo/debugjob/index.tmpl
  20. +1
    -1
      templates/repo/header.tmpl
  21. +1
    -0
      templates/repo/modelarts/inferencejob/index.tmpl
  22. +1
    -0
      templates/repo/modelarts/trainjob/index.tmpl
  23. +104
    -2
      web_src/less/openi.less

BIN
custom/public/img/ranking_list.jpg View File

Before After
Width: 600  |  Height: 544  |  Size: 37 kB

+ 98
- 25
models/cloudbrain.go View File

@@ -78,28 +78,30 @@ const (
)

type Cloudbrain struct {
ID int64 `xorm:"pk autoincr"`
JobID string `xorm:"INDEX NOT NULL"`
JobType string `xorm:"INDEX NOT NULL DEFAULT 'DEBUG'"`
JobName string
Status string
UserID int64
RepoID int64
SubTaskName string
ContainerID string
ContainerIp string
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
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:"-"`
CanModify bool `xorm:"-"`
Type int
ID int64 `xorm:"pk autoincr"`
JobID string `xorm:"INDEX NOT NULL"`
JobType string `xorm:"INDEX NOT NULL DEFAULT 'DEBUG'"`
JobName string
Status string
UserID int64
RepoID int64
SubTaskName string
ContainerID string
ContainerIp string
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
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:"-"`
CanModify bool `xorm:"-"`
Type int
BenchmarkTypeID int
BenchmarkChildTypeID int

VersionID int64 //版本id
VersionName string `xorm:"INDEX"` //当前版本
@@ -214,7 +216,7 @@ type CloudbrainsOptions struct {
CloudbrainIDs []int64
// JobStatus CloudbrainStatus
Type int
JobTypes []string
JobTypes []string
VersionName string
IsLatestVersion string
JobTypeNot bool
@@ -387,6 +389,24 @@ type Category struct {
Value string `json:"value"`
}

type BenchmarkTypes struct {
BenchmarkType []*BenchmarkType `json:"type"`
}

type BenchmarkType struct {
Id int `json:"id"`
First string `json:"first"` //一级算法类型名称
Second []*BenchmarkDataset `json:"second"`
}

type BenchmarkDataset struct {
Id int `json:"id"`
Value string `json:"value"` //二级算法类型名称
Attachment string `json:"attachment"` //数据集的uuid
Owner string `json:"owner"` //评估脚本所在仓库的拥有者
RepoName string `json:"repo_name"` //评估脚本所在仓库的名称
}

type GpuInfos struct {
GpuInfo []*GpuInfo `json:"gpu_type"`
}
@@ -442,6 +462,59 @@ type CommitImageResult struct {
Payload map[string]interface{} `json:"payload"`
}

type GetJobLogParams struct {
Size string `json:"size"`
Sort string `json:"sort"`
QueryInfo QueryInfo `json:"query"`
}

type QueryInfo struct {
MatchInfo MatchInfo `json:"match"`
}

type MatchInfo struct {
PodName string `json:"kubernetes.pod.name"`
}

type GetJobLogResult struct {
ScrollID string `json:"_scroll_id"`
Took int `json:"took"`
TimedOut bool `json:"timed_out"`
Shards struct {
Total int `json:"total"`
Successful int `json:"successful"`
Skipped int `json:"skipped"`
Failed int `json:"failed"`
} `json:"_shards"`
Hits struct {
Hits []Hits `json:"hits"`
} `json:"hits"`
}

type Hits struct {
Index string `json:"_index"`
Type string `json:"_type"`
ID string `json:"_id"`
Source struct {
Message string `json:"message"`
} `json:"_source"`
Sort []int `json:"sort"`
}

type GetAllJobLogParams struct {
Scroll string `json:"scroll"`
ScrollID string `json:"scroll_id"`
}

type DeleteJobLogTokenParams struct {
ScrollID string `json:"scroll_id"`
}

type DeleteJobLogTokenResult struct {
Succeeded bool `json:"succeeded"`
NumFreed int `json:"num_freed"`
}

type CloudBrainResult struct {
Code string `json:"code"`
Msg string `json:"msg"`
@@ -1221,8 +1294,8 @@ func GetCloudBrainUnStoppedJob() ([]*Cloudbrain, error) {
Find(&cloudbrains)
}

func GetCloudbrainCountByUserID(userID int64) (int, error) {
count, err := x.In("status", JobWaiting, JobRunning).And("job_type = ? and user_id = ? and type = ?", JobTypeDebug, userID, TypeCloudBrainOne).Count(new(Cloudbrain))
func GetCloudbrainCountByUserID(userID int64, jobType string) (int, error) {
count, err := x.In("status", JobWaiting, JobRunning).And("job_type = ? and user_id = ? and type = ?", jobType, userID, TypeCloudBrainOne).Count(new(Cloudbrain))
return int(count), err
}



+ 13
- 8
modules/auth/cloudbrain.go View File

@@ -6,14 +6,19 @@ import (
)

type CreateCloudBrainForm struct {
JobName string `form:"job_name" binding:"Required"`
Image string `form:"image" binding:"Required"`
Command string `form:"command" binding:"Required"`
Attachment string `form:"attachment" binding:"Required"`
JobType string `form:"job_type" binding:"Required"`
BenchmarkCategory string `form:"get_benchmark_category"`
GpuType string `form:"gpu_type"`
ResourceSpecId int `form:"resource_spec_id" binding:"Required"`
JobName string `form:"job_name" binding:"Required"`
Image string `form:"image" binding:"Required"`
Command string `form:"command" binding:"Required"`
Attachment string `form:"attachment" binding:"Required"`
JobType string `form:"job_type" binding:"Required"`
BenchmarkCategory string `form:"get_benchmark_category"`
GpuType string `form:"gpu_type"`
TrainUrl string `form:"train_url"`
TestUrl string `form:"test_url"`
Description string `form:"description"`
ResourceSpecId int `form:"resource_spec_id" binding:"Required"`
BenchmarkTypeID int `form:"benchmark_types_id"`
BenchmarkChildTypeID int `form:"benchmark_child_types_id"`
}

type CommitImageCloudBrainForm struct {


+ 40
- 32
modules/cloudbrain/cloudbrain.go View File

@@ -14,11 +14,16 @@ import (
)

const (
Command = `pip3 install jupyterlab==2.2.5 -i https://pypi.tuna.tsinghua.edu.cn/simple;service ssh stop;jupyter lab --no-browser --ip=0.0.0.0 --allow-root --notebook-dir="/code" --port=80 --LabApp.token="" --LabApp.allow_origin="self https://cloudbrain.pcl.ac.cn"`
Command = `pip3 install jupyterlab==2.2.5 -i https://pypi.tuna.tsinghua.edu.cn/simple;
service ssh stop;
jupyter lab --no-browser --ip=0.0.0.0 --allow-root --notebook-dir="/code" --port=80 --LabApp.token="" --LabApp.allow_origin="self https://cloudbrain.pcl.ac.cn"`
//CommandBenchmark = `echo "start benchmark";python /code/test.py;echo "end benchmark"`
CommandBenchmark = `echo "start benchmark";cd /benchmark && bash run_bk.sh;echo "end benchmark"`
CodeMountPath = "/code"
DataSetMountPath = "/dataset"
ModelMountPath = "/model"
BenchMarkMountPath = "/benchmark"
BenchMarkResourceID = 1
Snn4imagenetMountPath = "/snn4imagenet"
BrainScoreMountPath = "/brainscore"
TaskInfoName = "/taskInfo"
@@ -102,7 +107,7 @@ func AdminOrJobCreaterRight(ctx *context.Context) {

}

func GenerateTask(ctx *context.Context, jobName, image, command, uuid, codePath, modelPath, benchmarkPath, snn4imagenetPath, brainScorePath, jobType, gpuQueue string, resourceSpecId int) error {
func GenerateTask(ctx *context.Context, jobName, image, command, uuid, codePath, modelPath, benchmarkPath, snn4imagenetPath, brainScorePath, jobType, gpuQueue, description string, benchmarkTypeID, benchmarkChildTypeID, resourceSpecId int) error {
dataActualPath := setting.Attachment.Minio.RealPath +
setting.Attachment.Minio.Bucket + "/" +
setting.Attachment.Minio.BasePath +
@@ -201,19 +206,22 @@ func GenerateTask(ctx *context.Context, jobName, image, command, uuid, codePath,

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,
Image: image,
GpuQueue: gpuQueue,
ResourceSpecId: resourceSpecId,
ComputeResource: models.GPUResource,
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,
BenchmarkTypeID: benchmarkTypeID,
BenchmarkChildTypeID: benchmarkChildTypeID,
Description: description,
})

if err != nil {
@@ -270,7 +278,7 @@ func RestartTask(ctx *context.Context, task *models.Cloudbrain, newJobID *string
Volumes: []models.Volume{
{
HostPath: models.StHostPath{
Path: storage.GetMinioPath(jobName, CodeMountPath + "/"),
Path: storage.GetMinioPath(jobName, CodeMountPath+"/"),
MountPath: CodeMountPath,
ReadOnly: false,
},
@@ -284,28 +292,28 @@ func RestartTask(ctx *context.Context, task *models.Cloudbrain, newJobID *string
},
{
HostPath: models.StHostPath{
Path: storage.GetMinioPath(jobName, ModelMountPath + "/"),
Path: storage.GetMinioPath(jobName, ModelMountPath+"/"),
MountPath: ModelMountPath,
ReadOnly: false,
},
},
{
HostPath: models.StHostPath{
Path: storage.GetMinioPath(jobName, BenchMarkMountPath + "/"),
Path: storage.GetMinioPath(jobName, BenchMarkMountPath+"/"),
MountPath: BenchMarkMountPath,
ReadOnly: true,
},
},
{
HostPath: models.StHostPath{
Path: storage.GetMinioPath(jobName, Snn4imagenetMountPath + "/"),
Path: storage.GetMinioPath(jobName, Snn4imagenetMountPath+"/"),
MountPath: Snn4imagenetMountPath,
ReadOnly: true,
},
},
{
HostPath: models.StHostPath{
Path: storage.GetMinioPath(jobName, BrainScoreMountPath + "/"),
Path: storage.GetMinioPath(jobName, BrainScoreMountPath+"/"),
MountPath: BrainScoreMountPath,
ReadOnly: true,
},
@@ -323,18 +331,18 @@ func RestartTask(ctx *context.Context, task *models.Cloudbrain, newJobID *string

var jobID = jobResult.Payload["jobId"].(string)
newTask := &models.Cloudbrain{
Status: string(models.JobWaiting),
UserID: task.UserID,
RepoID: task.RepoID,
JobID: jobID,
JobName: task.JobName,
SubTaskName: task.SubTaskName,
JobType: task.JobType,
Type: task.Type,
Uuid: task.Uuid,
Image: task.Image,
GpuQueue: task.GpuQueue,
ResourceSpecId: task.ResourceSpecId,
Status: string(models.JobWaiting),
UserID: task.UserID,
RepoID: task.RepoID,
JobID: jobID,
JobName: task.JobName,
SubTaskName: task.SubTaskName,
JobType: task.JobType,
Type: task.Type,
Uuid: task.Uuid,
Image: task.Image,
GpuQueue: task.GpuQueue,
ResourceSpecId: task.ResourceSpecId,
ComputeResource: task.ComputeResource,
}



+ 101
- 0
modules/cloudbrain/resty.go View File

@@ -2,7 +2,10 @@ package cloudbrain

import (
"encoding/json"
"errors"
"fmt"
"net/http"
"strconv"
"strings"

"code.gitea.io/gitea/modules/log"
@@ -23,6 +26,8 @@ const (
JobHasBeenStopped = "S410"
Public = "public"
Custom = "custom"
LogPageSize = 500
LogPageTokenExpired = "5m"
)

func getRestyClient() *resty.Client {
@@ -270,3 +275,99 @@ sendjob:

return nil
}

func GetJobLog(jobID string) (*models.GetJobLogResult, error) {
checkSetting()
client := getRestyClient()
var result models.GetJobLogResult
req := models.GetJobLogParams{
Size: strconv.Itoa(LogPageSize),
Sort: "log.offset",
QueryInfo: models.QueryInfo{
MatchInfo: models.MatchInfo{
PodName: jobID + "-task1-0",
},
},
}

res, err := client.R().
SetHeader("Content-Type", "application/json").
SetAuthToken(TOKEN).
SetBody(req).
SetResult(&result).
Post(HOST + "es/_search?_source=message&scroll=" + LogPageTokenExpired)

if err != nil {
log.Error("GetJobLog failed: %v", err)
return &result, fmt.Errorf("resty GetJobLog: %v, %s", err, res.String())
}

if !strings.Contains(res.Status(), strconv.Itoa(http.StatusOK)) {
log.Error("res.Status(): %s, response: %s", res.Status(), res.String())
return &result, errors.New(res.String())
}

return &result, nil
}

func GetJobAllLog(scrollID string) (*models.GetJobLogResult, error) {
checkSetting()
client := getRestyClient()
var result models.GetJobLogResult
req := models.GetAllJobLogParams{
Scroll: LogPageTokenExpired,
ScrollID: scrollID,
}

res, err := client.R().
SetHeader("Content-Type", "application/json").
SetAuthToken(TOKEN).
SetBody(req).
SetResult(&result).
Post(HOST + "es/_search/scroll")

if err != nil {
log.Error("GetJobAllLog failed: %v", err)
return &result, fmt.Errorf("resty GetJobAllLog: %v, %s", err, res.String())
}

if !strings.Contains(res.Status(), strconv.Itoa(http.StatusOK)) {
log.Error("res.Status(): %s, response: %s", res.Status(), res.String())
return &result, errors.New(res.String())
}

return &result, nil
}

func DeleteJobLogToken(scrollID string) (error) {
checkSetting()
client := getRestyClient()
var result models.DeleteJobLogTokenResult
req := models.DeleteJobLogTokenParams{
ScrollID: scrollID,
}

res, err := client.R().
SetHeader("Content-Type", "application/json").
SetAuthToken(TOKEN).
SetBody(req).
SetResult(&result).
Delete(HOST + "es/_search/scroll")

if err != nil {
log.Error("DeleteJobLogToken failed: %v", err)
return fmt.Errorf("resty DeleteJobLogToken: %v, %s", err, res.String())
}

if !strings.Contains(res.Status(), strconv.Itoa(http.StatusOK)) {
log.Error("res.Status(): %s, response: %s", res.Status(), res.String())
return errors.New(res.String())
}

if !result.Succeeded {
log.Error("DeleteJobLogToken failed")
return errors.New("DeleteJobLogToken failed")
}

return nil
}

+ 13
- 5
modules/setting/setting.go View File

@@ -462,11 +462,15 @@ var (
MaxDuration int64

//benchmark config
IsBenchmarkEnabled bool
BenchmarkOwner string
BenchmarkName string
BenchmarkServerHost string
BenchmarkCategory string
IsBenchmarkEnabled bool
BenchmarkOwner string
BenchmarkName string
BenchmarkServerHost string
BenchmarkCategory string
BenchmarkTypes string
BenchmarkGpuTypes string
BenchmarkResourceSpecs string
BenchmarkMaxDuration int64

//snn4imagenet config
IsSnn4imagenetEnabled bool
@@ -1270,6 +1274,10 @@ func NewContext() {
BenchmarkName = sec.Key("NAME").MustString("")
BenchmarkServerHost = sec.Key("HOST").MustString("")
BenchmarkCategory = sec.Key("CATEGORY").MustString("")
BenchmarkTypes = sec.Key("TYPES").MustString("")
BenchmarkGpuTypes = sec.Key("GPU_TYPES").MustString("")
BenchmarkResourceSpecs = sec.Key("RESOURCE_SPECS").MustString("")
BenchmarkMaxDuration = sec.Key("MAX_DURATION").MustInt64(14400)

sec = Cfg.Section("snn4imagenet")
IsSnn4imagenetEnabled = sec.Key("ENABLED").MustBool(false)


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

@@ -933,6 +933,14 @@ modelarts.train_job_para_admin=train_job_para_admin
modelarts.train_job_para.edit=train_job_para.edit
modelarts.train_job_para.connfirm=train_job_para.connfirm


modelarts.evaluate_job=Model Evaluation
modelarts.evaluate_job.new_job=New Model Evaluation
cloudbrain.benchmark.evaluate_type=Evaluation Type
cloudbrain.benchmark.evaluate_child_type=Child Type
cloudbrain.benchmark.evaluate_mirror=Mirror
cloudbrain.benchmark.evaluate_train=Train Script
cloudbrain.benchmark.evaluate_test=Test Script
modelarts.infer_job_model = Model
modelarts.infer_job_model_file = Model File
modelarts.infer_job = Inference Job


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

@@ -941,6 +941,14 @@ modelarts.back=返回
modelarts.train_job_para_admin=任务参数管理
modelarts.train_job_para.edit=编辑
modelarts.train_job_para.connfirm=确定
modelarts.evaluate_job=评测任务
modelarts.evaluate_job.new_job=新建评测任务
cloudbrain.benchmark.evaluate_type=评测类型
cloudbrain.benchmark.evaluate_child_type=子类型
cloudbrain.benchmark.evaluate_mirror=镜像
cloudbrain.benchmark.evaluate_train=训练程序
cloudbrain.benchmark.evaluate_test=测试程序


modelarts.infer_job_model = 模型名称
modelarts.infer_job_model_file = 模型文件


+ 1
- 0
routers/api/v1/api.go View File

@@ -879,6 +879,7 @@ func RegisterRoutes(m *macaron.Macaron) {
}, reqAnyRepoReader())
m.Group("/cloudbrain", func() {
m.Get("/:jobid", repo.GetCloudbrainTask)
m.Get("/:jobid/log", repo.CloudbrainGetLog)
}, reqRepoReader(models.UnitTypeCloudBrain))
m.Group("/modelarts", func() {
m.Group("/notebook", func() {


+ 57
- 0
routers/api/v1/repo/cloudbrain.go View File

@@ -8,6 +8,7 @@ package repo
import (
"code.gitea.io/gitea/modules/log"
"net/http"
"sort"
"time"

"code.gitea.io/gitea/models"
@@ -91,3 +92,59 @@ func GetCloudbrainTask(ctx *context.APIContext) {
})

}

func CloudbrainGetLog(ctx *context.Context) {
jobID := ctx.Params(":jobid")
_, err := models.GetCloudbrainByJobID(jobID)
if err != nil {
log.Error("GetCloudbrainByJobID failed: %v", err, ctx.Data["MsgID"])
ctx.ServerError(err.Error(), err)
return
}

var hits []models.Hits
result, err := cloudbrain.GetJobLog(jobID)
if err != nil{
log.Error("GetJobLog failed: %v", err, ctx.Data["MsgID"])
ctx.ServerError(err.Error(), err)
return
}
hits = result.Hits.Hits

//if the size equal page_size, then take the scroll_id to get all log and delete the scroll_id(the num of scroll_id is limited)
if len(result.Hits.Hits) >= cloudbrain.LogPageSize {
for {
resultNext, err := cloudbrain.GetJobAllLog(result.ScrollID)
if err != nil{
log.Error("GetJobAllLog failed: %v", err, ctx.Data["MsgID"])
} else {
for _, hit := range resultNext.Hits.Hits {
hits = append(hits, hit)
}
}

if len(resultNext.Hits.Hits) < cloudbrain.LogPageSize {
log.Info("get all log already")
break
}
}
}

cloudbrain.DeleteJobLogToken(result.ScrollID)

sort.Slice(hits, func(i, j int) bool {
return hits[i].Sort[0] < hits[j].Sort[0]
})

var content string
for _, log := range hits {
content += log.Source.Message + "\n"
}

ctx.JSON(http.StatusOK, map[string]interface{}{
"JobID": jobID,
"Content": content,
})

return
}

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

@@ -6,11 +6,12 @@
package repo

import (
"code.gitea.io/gitea/modules/util"
"net/http"
"strconv"
"strings"

"code.gitea.io/gitea/modules/util"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"


+ 416
- 16
routers/repo/cloudbrain.go View File

@@ -28,15 +28,21 @@ import (
)

const (
tplCloudBrainIndex base.TplName = "repo/cloudbrain/index"
tplCloudBrainNew base.TplName = "repo/cloudbrain/new"
tplCloudBrainShow base.TplName = "repo/cloudbrain/show"
tplCloudBrainShowModels base.TplName = "repo/cloudbrain/models/index"

tplCloudBrainBenchmarkIndex base.TplName = "repo/cloudbrain/benchmark/index"
tplCloudBrainBenchmarkNew base.TplName = "repo/cloudbrain/benchmark/new"
tplCloudBrainBenchmarkShow base.TplName = "repo/cloudbrain/benchmark/show"
)

var (
gpuInfos *models.GpuInfos
categories *models.Categories
gpuInfos *models.GpuInfos
categories *models.Categories
benchmarkTypes *models.BenchmarkTypes
benchmarkGpuInfos *models.GpuInfos
benchmarkResourceSpecs *models.ResourceSpecs
)

var jobNamePattern = regexp.MustCompile(`^[a-z0-9][a-z0-9-_]{1,34}[a-z0-9-]$`)
@@ -124,11 +130,28 @@ func cloudBrainNewDataPrepare(ctx *context.Context) error {
}
ctx.Data["benchmark_categories"] = categories.Category

if benchmarkTypes == nil {
if err := json.Unmarshal([]byte(setting.BenchmarkTypes), &benchmarkTypes); err != nil {
log.Error("json.Unmarshal BenchmarkTypes(%s) failed:%v", setting.BenchmarkTypes, err, ctx.Data["MsgID"])
}
}
ctx.Data["benchmark_types"] = benchmarkTypes.BenchmarkType

if gpuInfos == nil {
json.Unmarshal([]byte(setting.GpuTypes), &gpuInfos)
}
ctx.Data["gpu_types"] = gpuInfos.GpuInfo

if benchmarkGpuInfos == nil {
json.Unmarshal([]byte(setting.BenchmarkGpuTypes), &benchmarkGpuInfos)
}
ctx.Data["benchmark_gpu_types"] = benchmarkGpuInfos.GpuInfo

if benchmarkResourceSpecs == nil {
json.Unmarshal([]byte(setting.BenchmarkResourceSpecs), &benchmarkResourceSpecs)
}
ctx.Data["benchmark_resource_specs"] = benchmarkResourceSpecs.ResourceSpec

if cloudbrain.ResourceSpecs == nil {
json.Unmarshal([]byte(setting.ResourceSpecs), &cloudbrain.ResourceSpecs)
}
@@ -155,9 +178,9 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) {
ctx.Data["PageIsCloudBrain"] = true
jobName := form.JobName
image := form.Image
command := form.Command
uuid := form.Attachment
jobType := form.JobType
command := cloudbrain.Command
gpuQueue := form.GpuType
codePath := setting.JobPath + jobName + cloudbrain.CodeMountPath
resourceSpecId := form.ResourceSpecId
@@ -174,7 +197,7 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) {
return
}

count, err := models.GetCloudbrainCountByUserID(ctx.User.ID)
count, err := models.GetCloudbrainCountByUserID(ctx.User.ID, jobType)
if err != nil {
log.Error("GetCloudbrainCountByUserID failed:%v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
@@ -238,12 +261,14 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) {
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)
storage.GetMinioPath(jobName, cloudbrain.BrainScoreMountPath+"/"), jobType, gpuQueue, form.Description,
0, 0, resourceSpecId)
if err != nil {
cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr(err.Error(), tplCloudBrainNew, &form)
return
}

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

@@ -276,7 +301,7 @@ func CloudBrainRestart(ctx *context.Context) {
break
}

count, err := models.GetCloudbrainCountByUserID(ctx.User.ID)
count, err := models.GetCloudbrainCountByUserID(ctx.User.ID, string(models.JobTypeDebug))
if err != nil {
log.Error("GetCloudbrainCountByUserID failed:%v", err, ctx.Data["MsgID"])
resultCode = "-1"
@@ -310,7 +335,15 @@ func CloudBrainRestart(ctx *context.Context) {
})
}

func CloudBrainBenchMarkShow(ctx *context.Context) {
cloudBrainShow(ctx, tplCloudBrainBenchmarkShow)
}

func CloudBrainShow(ctx *context.Context) {
cloudBrainShow(ctx, tplCloudBrainShow)
}

func cloudBrainShow(ctx *context.Context, tpName base.TplName) {
ctx.Data["PageIsCloudBrain"] = true

var jobID = ctx.Params(":jobid")
@@ -327,6 +360,8 @@ func CloudBrainShow(ctx *context.Context) {
if result != nil {
jobRes, _ := models.ConvertToJobResultPayload(result.Payload)
jobRes.Resource.Memory = strings.ReplaceAll(jobRes.Resource.Memory, "Mi", "MB")
spec := "GPU数:" + strconv.Itoa(jobRes.Resource.NvidiaComGpu) + ",CPU数:" + strconv.Itoa(jobRes.Resource.CPU) + ",内存(MB):" + jobRes.Resource.Memory
ctx.Data["resource_spec"] = spec
taskRoles := jobRes.TaskRoles
if jobRes.JobStatus.State != string(models.JobFailed) {
taskRes, _ := models.ConvertToTaskPod(taskRoles[cloudbrain.SubTaskName].(map[string]interface{}))
@@ -351,11 +386,28 @@ func CloudBrainShow(ctx *context.Context) {
}

ctx.Data["result"] = jobRes
} else {
log.Info("error:" + err.Error())
}
user, err := models.GetUserByID(task.UserID)
if err == nil {
task.User = user
}

var duration int64
if task.Status == string(models.JobRunning) {
duration = time.Now().Unix() - int64(task.CreatedUnix)
} else {
duration = int64(task.UpdatedUnix) - int64(task.CreatedUnix)
}
ctx.Data["duration"] = util.AddZero(duration/3600000) + ":" + util.AddZero(duration%3600000/60000) + ":" + util.AddZero(duration%60000/1000)
ctx.Data["task"] = task
ctx.Data["jobID"] = jobID
ctx.HTML(200, tplCloudBrainShow)
ctx.Data["jobName"] = task.JobName
version_list_task := make([]*models.Cloudbrain, 0)
version_list_task = append(version_list_task, task)
ctx.Data["version_list_task"] = version_list_task
ctx.HTML(200, tpName)
}

func CloudBrainDebug(ctx *context.Context) {
@@ -393,7 +445,7 @@ func CloudBrainStop(ctx *context.Context) {

task := ctx.Cloudbrain
for {
if task.Status == string(models.JobStopped) || task.Status == string(models.JobFailed) {
if task.Status == string(models.JobStopped) || task.Status == string(models.JobFailed) || task.Status == string(models.JobSucceeded){
log.Error("the job(%s) has been stopped", task.JobName, ctx.Data["msgID"])
resultCode = "-1"
errorMsg = "system error"
@@ -510,22 +562,31 @@ func logErrorAndUpdateJobStatus(err error, taskInfo *models.Cloudbrain) {
}

func CloudBrainDel(ctx *context.Context) {
if err := deleteCloudbrainJob(ctx); err != nil {
log.Error("deleteCloudbrainJob failed: %v", err, ctx.Data["msgID"])
ctx.ServerError(err.Error(), err)
return
}
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob?debugListType=all")
}

func deleteCloudbrainJob(ctx *context.Context) error {
task := ctx.Cloudbrain

if task.Status != string(models.JobStopped) && task.Status != string(models.JobFailed) {
if task.Status != string(models.JobStopped) && task.Status != string(models.JobFailed) && task.Status != string(models.JobSucceeded) {
log.Error("the job(%s) has not been stopped", task.JobName, ctx.Data["msgID"])
ctx.ServerError("the job has not been stopped", errors.New("the job has not been stopped"))
return
return errors.New("the job has not been stopped")
}

err := models.DeleteJob(task)
if err != nil {
ctx.ServerError("DeleteJob failed", err)
return
log.Error("DeleteJob failed: %v", err, ctx.Data["msgID"])
return err
}

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

return nil
}

func CloudBrainShowModels(ctx *context.Context) {
@@ -632,6 +693,12 @@ func CloudBrainDownloadModel(ctx *context.Context) {
}

func GetRate(ctx *context.Context) {
isObjectDetcionAll := ctx.QueryBool("isObjectDetcionAll")
if isObjectDetcionAll {
ctx.Redirect(setting.BenchmarkServerHost + "?username=admin")
return
}

var jobID = ctx.Params(":jobid")
job, err := models.GetCloudbrainByJobID(jobID)
if err != nil {
@@ -640,6 +707,7 @@ func GetRate(ctx *context.Context) {
}

if job.JobType == string(models.JobTypeBenchmark) {
log.Info("url=" + setting.BenchmarkServerHost + "?username=" + ctx.User.Name)
ctx.Redirect(setting.BenchmarkServerHost + "?username=" + ctx.User.Name)
} else if job.JobType == string(models.JobTypeSnn4imagenet) {
ctx.Redirect(setting.Snn4imagenetServerHost)
@@ -855,7 +923,14 @@ func SyncCloudbrainStatus() {
log.Error("UpdateJob(%s) failed:%v", task.JobName, err)
}

if task.Duration >= setting.MaxDuration {
var maxDuration int64
if task.JobType == string(models.JobTypeBenchmark) {
maxDuration = setting.BenchmarkMaxDuration
} else {
maxDuration = setting.MaxDuration
}

if task.Duration >= maxDuration {
log.Info("begin to stop job(%s), because of the duration", task.JobName)
err = cloudbrain.StopJob(task.JobID)
if err != nil {
@@ -923,3 +998,328 @@ func SyncCloudbrainStatus() {

return
}

func CloudBrainBenchmarkIndex(ctx *context.Context) {
MustEnableCloudbrain(ctx)
repo := ctx.Repo.Repository
page := ctx.QueryInt("page")
if page <= 0 {
page = 1
}

var jobTypes []string
jobTypes = append(jobTypes, string(models.JobTypeBenchmark))
ciTasks, count, err := models.Cloudbrains(&models.CloudbrainsOptions{
ListOptions: models.ListOptions{
Page: page,
PageSize: setting.UI.IssuePagingNum,
},
RepoID: repo.ID,
Type: models.TypeCloudBrainOne,
JobTypes: jobTypes,
})
if err != nil {
ctx.ServerError("Get debugjob faild:", err)
return
}

for i, task := range ciTasks {
ciTasks[i].CanDel = cloudbrain.CanDeleteJob(ctx, &task.Cloudbrain)
ciTasks[i].Cloudbrain.ComputeResource = task.ComputeResource
var duration int64
if task.Status == string(models.JobRunning) {
duration = time.Now().Unix() - int64(task.Cloudbrain.CreatedUnix)
} else {
duration = int64(task.Cloudbrain.UpdatedUnix) - int64(task.Cloudbrain.CreatedUnix)
}
ciTasks[i].TrainJobDuration = util.AddZero(duration/3600000) + ":" + util.AddZero(duration%3600000/60000) + ":" + util.AddZero(duration%60000/1000)
}

pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, 5)

ctx.Data["Page"] = pager
ctx.Data["PageIsCloudBrain"] = true
ctx.Data["Tasks"] = ciTasks
ctx.Data["CanCreate"] = cloudbrain.CanCreateOrDebugJob(ctx)
ctx.Data["RepoIsEmpty"] = repo.IsEmpty
ctx.HTML(200, tplCloudBrainBenchmarkIndex)
}

func GetChildTypes(ctx *context.Context) {
benchmarkTypeID := ctx.QueryInt("benchmark_type_id")
re := make(map[string]interface{})
for {
if benchmarkTypes == nil {
if err := json.Unmarshal([]byte(setting.BenchmarkTypes), &benchmarkTypes); err != nil {
log.Error("json.Unmarshal BenchmarkTypes(%s) failed:%v", setting.BenchmarkTypes, err, ctx.Data["MsgID"])
re["errMsg"] = "system error"
break
}
}
var isExist bool
for _, benchmarkType := range benchmarkTypes.BenchmarkType {
if benchmarkTypeID == benchmarkType.Id {
isExist = true
re["child_types"] = benchmarkType.Second
re["result_code"] = "0"
break
}
}
if !isExist {
re["result_code"] = "1"
log.Error("no such benchmark_type_id", ctx.Data["MsgID"])
re["errMsg"] = "system error"
break
}
break
}
ctx.JSON(200, re)
}

func CloudBrainBenchmarkNew(ctx *context.Context) {
err := cloudBrainNewDataPrepare(ctx)
if err != nil {
ctx.ServerError("get new cloudbrain info failed", err)
return
}
ctx.HTML(200, tplCloudBrainBenchmarkNew)
}

func getBenchmarkAttachment(benchmarkTypeID, benchmarkChildTypeID int) (*models.BenchmarkDataset, error) {
var childInfo *models.BenchmarkDataset
if benchmarkTypes == nil {
if err := json.Unmarshal([]byte(setting.BenchmarkTypes), &benchmarkTypes); err != nil {
log.Error("json.Unmarshal BenchmarkTypes(%s) failed:%v", setting.BenchmarkTypes, err)
return childInfo, err
}
}

var isExist bool
for _, benchmarkType := range benchmarkTypes.BenchmarkType {
if benchmarkType.Id == benchmarkTypeID {
for _, childType := range benchmarkType.Second {
if childType.Id == benchmarkChildTypeID {
childInfo = childType
isExist = true
break
}
}
break
}
}

if !isExist {
log.Error("no such benchmark_type_id&benchmark_child_type_id")
return childInfo, errors.New("no such benchmark_type_id&benchmark_child_type_id")
}

return childInfo, nil
}

func getBenchmarkGpuQueue(gpuQueue string) (string, error) {
queue := ""
if benchmarkGpuInfos == nil {
if err := json.Unmarshal([]byte(setting.BenchmarkGpuTypes), &benchmarkGpuInfos); err != nil {
log.Error("json.Unmarshal BenchmarkGpuTypes(%s) failed:%v", setting.BenchmarkGpuTypes, err)
return queue, err
}
}

var isExist bool
for _, gpuInfo := range benchmarkGpuInfos.GpuInfo {
if gpuQueue == gpuInfo.Queue {
isExist = true
queue = gpuQueue
break
}
}

if !isExist {
log.Error("no such gpuQueue, %s", gpuQueue)
return queue, errors.New("no such gpuQueue")
}

return queue, nil
}

func getBenchmarkResourceSpec(resourceSpecID int) (int, error) {
var id int
if benchmarkResourceSpecs == nil {
if err := json.Unmarshal([]byte(setting.BenchmarkResourceSpecs), &benchmarkResourceSpecs); err != nil {
log.Error("json.Unmarshal BenchmarkResourceSpecs(%s) failed:%v", setting.BenchmarkResourceSpecs, err)
return id, err
}
}

var isExist bool
for _, resourceSpec := range benchmarkResourceSpecs.ResourceSpec {
if resourceSpecID == resourceSpec.Id {
isExist = true
id = resourceSpecID
break
}
}

if !isExist {
log.Error("no such resourceSpecID, %d", resourceSpecID)
return id, errors.New("no such resourceSpec")
}

return id, nil
}

func CloudBrainBenchmarkCreate(ctx *context.Context, form auth.CreateCloudBrainForm) {
ctx.Data["PageIsCloudBrain"] = true
jobName := form.JobName
image := form.Image
gpuQueue := form.GpuType
command := cloudbrain.CommandBenchmark
codePath := setting.JobPath + jobName + cloudbrain.CodeMountPath
resourceSpecId := cloudbrain.BenchMarkResourceID
benchmarkTypeID := form.BenchmarkTypeID
benchmarkChildTypeID := form.BenchmarkChildTypeID

if !jobNamePattern.MatchString(jobName) {
ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_jobname_err"), tplCloudBrainBenchmarkNew, &form)
return
}

childInfo, err := getBenchmarkAttachment(benchmarkTypeID, benchmarkChildTypeID)
if err != nil {
log.Error("getBenchmarkAttachment failed:%v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr("benchmark type error", tplCloudBrainBenchmarkNew, &form)
return
}

_, err = getBenchmarkGpuQueue(gpuQueue)
if err != nil {
log.Error("getBenchmarkGpuQueue failed:%v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr("gpu queue error", tplCloudBrainBenchmarkNew, &form)
return
}

_, err = getBenchmarkResourceSpec(resourceSpecId)
if err != nil {
log.Error("getBenchmarkResourceSpec failed:%v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr("resource spec error", tplCloudBrainBenchmarkNew, &form)
return
}

count, err := models.GetCloudbrainCountByUserID(ctx.User.ID, string(models.JobTypeBenchmark))
if err != nil {
log.Error("GetCloudbrainCountByUserID failed:%v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr("system error", tplCloudBrainBenchmarkNew, &form)
return
} else {
if count >= 1 {
log.Error("the user already has running or waiting task", ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr("you have already a running or waiting task, can not create more", tplCloudBrainBenchmarkNew, &form)
return
}
}

_, err = models.GetCloudbrainByName(jobName)
if err == nil {
log.Error("the job name did already exist", ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr("the job name did already exist", tplCloudBrainBenchmarkNew, &form)
return
} else {
if !models.IsErrJobNotExist(err) {
log.Error("GetCloudbrainByName failed, %v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr("system error", tplCloudBrainBenchmarkNew, &form)
return
}
}
repo := ctx.Repo.Repository
os.RemoveAll(codePath)
if err := downloadCode(repo, codePath); err != nil {
log.Error("downloadCode failed, %v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr("system error", tplCloudBrainBenchmarkNew, &form)
return
}

if _, err := os.Stat(codePath + "/train.py"); err != nil {
if os.IsNotExist(err) {
// file does not exist
log.Error("train.py does not exist, %v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr("train.py does not exist", tplCloudBrainBenchmarkNew, &form)
} else {
log.Error("Stat failed, %v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr("system error", tplCloudBrainBenchmarkNew, &form)
}
return
} else if _, err := os.Stat(codePath + "/test.py"); err != nil {
if os.IsNotExist(err) {
// file does not exist
log.Error("test.py does not exist, %v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr("test.py does not exist", tplCloudBrainBenchmarkNew, &form)
} else {
log.Error("Stat failed, %v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr("system error", tplCloudBrainBenchmarkNew, &form)
}
return
}

if err := uploadCodeToMinio(codePath+"/", jobName, cloudbrain.CodeMountPath+"/"); err != nil {
log.Error("uploadCodeToMinio failed, %v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr("system error", tplCloudBrainBenchmarkNew, &form)
return
}

benchmarkPath := setting.JobPath + jobName + cloudbrain.BenchMarkMountPath
var gpuType string
for _, gpuInfo := range gpuInfos.GpuInfo {
if gpuInfo.Queue == gpuQueue {
gpuType = gpuInfo.Value
}
}

if err := downloadRateCode(repo, jobName, childInfo.Owner, childInfo.RepoName, benchmarkPath, form.BenchmarkCategory, gpuType); err != nil {
log.Error("downloadRateCode failed, %v", err, ctx.Data["MsgID"])
//cloudBrainNewDataPrepare(ctx)
//ctx.RenderWithErr("system error", tplCloudBrainBenchmarkNew, &form)
//return
}

if err := uploadCodeToMinio(benchmarkPath+"/", jobName, cloudbrain.BenchMarkMountPath+"/"); err != nil {
log.Error("uploadCodeToMinio failed, %v", err, ctx.Data["MsgID"])
//cloudBrainNewDataPrepare(ctx)
//ctx.RenderWithErr("system error", tplCloudBrainBenchmarkNew, &form)
//return
}

err = cloudbrain.GenerateTask(ctx, jobName, image, command, childInfo.Attachment, 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+"/"), string(models.JobTypeBenchmark), gpuQueue, form.Description,
benchmarkTypeID, benchmarkChildTypeID, resourceSpecId)
if err != nil {
cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr(err.Error(), tplCloudBrainBenchmarkNew, &form)
return
}

ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/cloudbrain/benchmark")
}

func BenchmarkDel(ctx *context.Context) {
if err := deleteCloudbrainJob(ctx); err != nil {
log.Error("deleteCloudbrainJob failed: %v", err, ctx.Data["msgID"])
ctx.ServerError(err.Error(), err)
return
}
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/cloudbrain/benchmark")
}

+ 10
- 10
routers/repo/modelarts.go View File

@@ -64,7 +64,7 @@ func DebugJobIndex(ctx *context.Context) {
}

var jobTypes []string
jobTypes = append(jobTypes, string(models.JobTypeBenchmark), string(models.JobTypeSnn4imagenet), string(models.JobTypeBrainScore), string(models.JobTypeDebug))
jobTypes = append(jobTypes, string(models.JobTypeSnn4imagenet), string(models.JobTypeBrainScore), string(models.JobTypeDebug))
ciTasks, count, err := models.Cloudbrains(&models.CloudbrainsOptions{
ListOptions: models.ListOptions{
Page: page,
@@ -387,7 +387,7 @@ func TrainJobIndex(ctx *context.Context) {
RepoID: repo.ID,
Type: models.TypeCloudBrainTwo,
JobTypeNot: false,
JobTypes: jobTypes,
JobTypes: jobTypes,
IsLatestVersion: modelarts.IsLatestVersion,
})
if err != nil {
@@ -1321,10 +1321,10 @@ func TrainJobShow(ctx *context.Context) {
Page: page,
PageSize: setting.UI.IssuePagingNum,
},
RepoID: repo.ID,
Type: models.TypeCloudBrainTwo,
RepoID: repo.ID,
Type: models.TypeCloudBrainTwo,
JobTypes: jobTypes,
JobID: jobID,
JobID: jobID,
})

if err != nil {
@@ -1438,10 +1438,10 @@ func TrainJobDel(ctx *context.Context) {
var jobTypes []string
jobTypes = append(jobTypes, string(models.JobTypeTrain))
VersionListTasks, _, err := models.CloudbrainsVersionList(&models.CloudbrainsOptions{
RepoID: repo.ID,
Type: models.TypeCloudBrainTwo,
RepoID: repo.ID,
Type: models.TypeCloudBrainTwo,
JobTypes: jobTypes,
JobID: jobID,
JobID: jobID,
})
if err != nil {
ctx.ServerError("get VersionListTasks failed", err)
@@ -1747,8 +1747,8 @@ func InferenceJobIndex(ctx *context.Context) {
Page: page,
PageSize: setting.UI.IssuePagingNum,
},
RepoID: repo.ID,
Type: models.TypeCloudBrainTwo,
RepoID: repo.ID,
Type: models.TypeCloudBrainTwo,
JobTypes: jobTypes,
})
if err != nil {


+ 13
- 0
routers/routes/routes.go View File

@@ -979,6 +979,19 @@ func RegisterRoutes(m *macaron.Macaron) {
})
m.Get("/create", reqRepoCloudBrainWriter, repo.CloudBrainNew)
m.Post("/create", reqRepoCloudBrainWriter, bindIgnErr(auth.CreateCloudBrainForm{}), repo.CloudBrainCreate)

m.Group("/benchmark", func() {
m.Get("", reqRepoCloudBrainReader, repo.CloudBrainBenchmarkIndex)
m.Group("/:jobid", func() {
m.Get("", reqRepoCloudBrainReader, repo.CloudBrainBenchMarkShow)
m.Post("/stop", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.CloudBrainStop)
m.Post("/del", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.BenchmarkDel)
m.Get("/rate", reqRepoCloudBrainReader, repo.GetRate)
})
m.Get("/create", reqRepoCloudBrainWriter, repo.CloudBrainBenchmarkNew)
m.Post("/create", reqRepoCloudBrainWriter, bindIgnErr(auth.CreateCloudBrainForm{}), repo.CloudBrainBenchmarkCreate)
m.Get("/get_child_types", repo.GetChildTypes)
})
}, context.RepoRef())
m.Group("/modelmanage", func() {
m.Post("/create_model", reqRepoModelManageWriter, repo.SaveModel)


+ 387
- 0
templates/repo/cloudbrain/benchmark/index.tmpl View File

@@ -0,0 +1,387 @@
<!-- 头部导航栏 -->
{{template "base/head" .}}

<style>
.fontsize14{
font-size: 14px;
}
.padding0{
padding: 0 !important;
}
</style>

<!-- 弹窗 -->
<div id="mask">
<div id="loadingPage">
<div class="rect1"></div>
<div class="rect2"></div>
<div class="rect3"></div>
<div class="rect4"></div>
<div class="rect5"></div>
</div>
</div>

<!-- 提示框 -->
<div class="alert"></div>

<div class="repository release dataset-list view">
{{template "repo/header" .}}
<!-- 列表容器 -->
<div class="ui container">
{{template "base/alert" .}}
<div class="ui two column stackable grid ">
<div class="column">
<div class="ui blue small menu compact selectcloudbrain">
<a class="item" href="{{.RepoLink}}/debugjob?debugListType=all">{{$.i18n.Tr "repo.modelarts.notebook"}}</a>
<a class="item" href="{{.RepoLink}}/modelarts/train-job">{{$.i18n.Tr "repo.modelarts.train_job"}}</a>
<a class="item" href="{{.RepoLink}}/modelarts/inference-job">{{$.i18n.Tr "repo.modelarts.infer_job"}}</a>
<a class="active item" href="{{.RepoLink}}/cloudbrain/benchmark">{{$.i18n.Tr "repo.modelarts.evaluate_job"}}</a>
</div>
</div>
<div class="column right aligned">
<a class="ui compact orange basic icon button" href="{{$.RepoLink}}/cloudbrain/123/rate?isObjectDetcionAll=true" style="box-shadow: none;" target="_blank"><i class="large ri-trophy-fill middle aligned icon"></i>基准测试排行榜</a>
{{if .Permission.CanWrite $.UnitTypeCloudBrain}}
<a class="ui green button" href="{{.RepoLink}}/cloudbrain/benchmark/create">{{$.i18n.Tr "repo.modelarts.evaluate_job.new_job"}}</a>
{{else}}
<a class="ui disabled button" >{{$.i18n.Tr "repo.modelarts.evaluate_job.new_job"}}</a>
{{end}}
</div>
</div>
{{if eq 0 (len .Tasks)}}
<div class="ui placeholder segment bgtask-none">
<div class="ui icon header bgtask-header-pic"></div>
<div class="bgtask-content-header">未创建过评测任务</div>
<div class="bgtask-content">
{{if $.RepoIsEmpty}}
<div class="bgtask-content-txt">代码版本:您还没有初始化代码仓库,请先<a href="{{.RepoLink}}">创建代码版本;</a></div>
{{end}}
<div class="bgtask-content-txt">使用说明:可以参考启智AI协作平台<a href="https://git.openi.org.cn/zeizei/OpenI_Learning">小白训练营课程。</a></div>
</div>
</div>
{{else}}
<!-- 中下列表展示区 -->
<div class="ui grid">
<div class="row">
<div class="ui sixteen wide column">
<!-- 任务展示 -->
<div class="dataset list">

<!-- 表头 -->
<div class="ui grid stackable" style="background: #f0f0f0;;">
<div class="row">
<div class="three wide column padding0">
<span style="margin:0 6px">{{$.i18n.Tr "repo.cloudbrain_task"}}</span>
</div>
<div class="two wide column text center padding0">
<span>{{$.i18n.Tr "repo.modelarts.status"}}</span>
</div>
<div class="two wide column text center padding0">
<span>{{$.i18n.Tr "repo.modelarts.createtime"}}</span>
</div>
<div class="two wide column text center padding0">
<span>{{$.i18n.Tr "repo.cloudbrain_status_runtime"}}</span>
</div>
<div class="two wide column text center padding0">
<span>{{$.i18n.Tr "repo.modelarts.computing_resources"}}</span>
</div>
<div class="one wide column text center padding0">
<span>{{$.i18n.Tr "repo.cloudbrain_creator"}}</span>
</div>
<div class="three wide column text center padding0">
<span>{{$.i18n.Tr "repo.cloudbrain_operate"}}</span>
</div>
</div>
</div>

{{range .Tasks}}
<div class="ui grid stackable item">
<div class="row">
<!-- 任务名 -->
<div class="three wide column padding0">
<a class="title" href="{{$.Link}}/{{.JobID}}" title="{{.JobName}}" style="font-size: 14px;">
<span class="fitted" style="width: 90%;vertical-align: middle;">{{.JobName}}</span>
</a>
</div>
<!-- 任务状态 -->
<div class="two wide column padding0" style="padding-left: 2.2rem !important;">
<span class="job-status" id="{{.JobID}}" data-repopath="{{$.RepoRelPath}}" data-jobid="{{.JobID}}" data-version="{{.VersionName}}">
<span><i id="{{.JobID}}-icon" style="vertical-align: middle;" class="{{.Status}}"></i><span id="{{.JobID}}-text" style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span>
</span>
</div>
<!-- 任务创建时间 -->
<div class="two wide column text center padding0">
<span style="font-size: 12px;" class="">{{TimeSinceUnix .Cloudbrain.CreatedUnix $.Lang}}</span>
</div>
<!-- 任务运行时间 -->
<div class="two wide column text center padding0">
<span style="font-size: 12px;" id="duration-{{.JobID}}">{{.TrainJobDuration}}</span>
</div>
<!-- 计算资源 -->
<div class="two wide column text center padding0">
<span style="font-size: 12px;">{{.ComputeResource}}</span>
</div>
<!-- 创建者 -->
<div class="one wide column text center padding0">
{{if .User.Name}}
<a href="{{AppSubUrl}}/{{.User.Name}}" title="{{.User.Name}}"><img class="ui avatar image" src="{{.User.RelAvatarLink}}"></a>
{{else}}
<a title="Ghost"><img class="ui avatar image" src="{{AppSubUrl}}/user/avatar/Ghost/-1"></a>
{{end}}
</div>

<div class="three wide column text center padding0">
<div class="ui compact buttons" >
<!-- 停止任务 -->
<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" "SUCCEEDED"}}disabled {{else}}blue {{end}}button' onclick='stopDebug("{{.JobID}}","{{$.RepoLink}}/cloudbrain/benchmark/{{.JobID}}/stop")'>
{{$.i18n.Tr "repo.stop"}}
</a>
{{else}}
<a class="ui basic disabled button">
{{$.i18n.Tr "repo.stop"}}
</a>
{{end}}
</form>

<a class="ui basic blue button" href="{{$.RepoLink}}/cloudbrain/{{.JobID}}/rate" target="_blank">
评分
</a>

<!-- 删除任务 -->
<form id="delForm-{{.JobID}}" action="{{if eq .ComputeResource "CPU/GPU"}}{{$.RepoLink}}/cloudbrain/benchmark{{else}}{{$.RepoLink}}/modelarts/notebook{{end}}/{{.JobID}}/del" method="post">
<input type="hidden" name="debugListType" value="all">
{{$.CsrfTokenHtml}}
{{if .CanDel}}
<a id="model-delete-{{.JobID}}" class='ui basic {{if eq .Status "STOPPED" "FAILED" "START_FAILED" "SUCCEEDED"}}blue {{else}}disabled {{end}}button' onclick="assertDelete(this)" style="border-radius: .28571429rem;">
{{$.i18n.Tr "repo.delete"}}
</a>
{{else}}
<a class="ui basic button disabled" onclick="assertDelete(this)" style="border-radius: .28571429rem;">
{{$.i18n.Tr "repo.delete"}}
</a>
{{end}}
</form>
</div>
</div>
</div>
</div>
{{end}}

<!--
<div class="" style="margin-top: 3.0em;">
<img class="ui middle aligned tiny image" src="/img/ranking_list.jpg">
<a class="ui blue" href="{{$.RepoLink}}/cloudbrain/123/rate?isObjectDetcionAll=true" target="_blank">目标检测算法排行榜</a>
</div>
-->
{{template "base/paginate" .}}
</div>

</div>
</div>
</div>
{{end}}

</div>

</div>
</div>

</div>

<!-- 确认模态框 -->
<div id="deletemodel">
<div class="ui basic modal">
<div class="ui icon header">
<i class="trash icon"></i> 删除任务
</div>

<div class="content">
<p>你确认删除该任务么?此任务一旦删除不可恢复。</p>
</div>
<div class="actions">
<div class="ui red basic inverted cancel button">
<i class="remove icon"></i> 取消操作
</div>
<div class="ui green basic inverted ok button">
<i class="checkmark icon"></i> 确定操作
</div>
</div>
</div>
</div>

</div>
{{template "base/footer" .}}

<script>
console.log({{.Tasks}})
// 调试和评分新开窗口
function stop(obj) {
if (obj.style.color != "rgb(204, 204, 204)") {
obj.target = '_blank'
} else {
return
}
}

// 删除时用户确认
function assertDelete(obj) {
if (obj.style.color == "rgb(204, 204, 204)") {
return
} else {
var delId = obj.parentNode.id
flag = 1;
$('.ui.basic.modal')
.modal({
onDeny: function() {
flag = false
},
onApprove: function() {
document.getElementById(delId).submit()
flag = true
},
onHidden: function() {
if (flag == false) {
$('.alert').html('您已取消操作').removeClass('alert-success').addClass('alert-danger').show().delay(1500).fadeOut();
}
}
})
.modal('show')
}
}
function runtime(time){
if(time){
let hours = time/3600000<10 ? "0"+parseInt(time/3600000):parseInt(time/3600000)
let miuns = time%3600000/60000<10 ? "0"+parseInt(time%3600000/60000):parseInt(time%3600000/60000)
let seconds = time%60000/1000<10 ? "0"+parseInt(time%60000/1000):parseInt(time%60000/1000)
return hours + ":" + miuns + ":" + seconds
}else{
return "00:00:00"
}
}

// 加载任务状态
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 computeResource = job.dataset.resource
const initArray = ['STOPPED','FAILED','START_FAILED','CREATE_FAILED','SUCCEEDED']
if (initArray.includes(job.textContent.trim())) {
return
}
const diffResource = computeResource == "NPU" ? 'modelarts/notebook' : 'cloudbrain'
$.get(`/api/v1/repos/${repoPath}/${diffResource}/${jobID}`, (data) => {
const jobID = data.JobID
const status = data.JobStatus
if (status != job.textContent.trim()) {
$('#' + jobID+'-icon').removeClass().addClass(status)
$('#' + jobID+ '-text').text(status)
}
if(status==="RUNNING"){
$('#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').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').addClass('blue')
}
if(["CREATING","STOPPING","STARTING","STOPPED","FAILED","START_FAILED","SUCCEEDED"].includes(status)){
$('#stop-model-debug-'+jobID).removeClass('blue').addClass('disabled')
}
if(status==="STOPPED" || status==="FAILED"|| status==="START_FAILED"){
$('#model-delete-'+jobID).removeClass('disabled').addClass('blue')
}else{
$('#model-delete-'+jobID).removeClass('blue').addClass('disabled')
}
}).fail(function(err) {
console.log(err);
});
});
};
// 获取弹窗
var modal = document.getElementById('imageModal');

// 打开弹窗的按钮对象
var btns = document.getElementsByClassName("imageBtn");

// 获取 <span> 元素,用于关闭弹窗
var spans = document.getElementsByClassName('close');

// 点击按钮打开弹窗
for (i = 0; i < btns.length; i++) {
btns[i].onclick = function() {
modal.style.display = "block";
}
}

// 点击 <span> (x), 关闭弹窗
for (i = 0; i < spans.length; i++) {
spans[i].onclick = function() {
modal.style.display = "none";
}
}

// 在用户点击其他地方时,关闭弹窗
window.onclick = function(event) {
if (event.target == modal) {
modal.style.display = "none";
}
}
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{
$('.alert').html(res.error_msg).removeClass('alert-success').addClass('alert-danger').show().delay(2000).fadeOut();
}
},
error :function(res){
console.log(res)

}
})

}

</script>

+ 243
- 0
templates/repo/cloudbrain/benchmark/new.tmpl View File

@@ -0,0 +1,243 @@
{{template "base/head" .}}
<style>

.unite{
font-family: SourceHanSansSC-medium !important;
color: rgba(16, 16, 16, 100) !important;
}

.title{
font-size: 16px !important;
padding-left: 3rem !important;
}
.min_title{
font-size: 14px !important;
padding-left: 6rem !important;
margin-bottom: 2rem !important;

}
.width{
width:100% !important;
}
.width80{
width: 80.7% !important;
margin-left: 10px;
}
.width85{
width: 85% !important;
margin-left: 4.5rem !important;
}
.width81{
margin-left: 1.5rem;
width: 81% !important;
}

.add{font-size: 18px;
padding: 0.5rem;
border: 1px solid rgba(187, 187, 187, 100);
border-radius: 0px 5px 5px 0px;
line-height: 21px;
text-align: center;
color: #C2C7CC;
}
.min{
font-size: 18px;
padding: 0.5rem;
border: 1px solid rgba(187, 187, 187, 100);
border-radius: 5px 0px 0px 5px;
line-height: 21px;
text-align: center;
color: #C2C7CC;
}

</style>
<!-- <div class="ui page dimmer">
<div class="ui text loader">{{.i18n.Tr "loading"}}</div>
</div> -->
<div id="mask">
<div id="loadingPage">
<div class="rect1"></div>
<div class="rect2"></div>
<div class="rect3"></div>
<div class="rect4"></div>
<div class="rect5"></div>
</div>
</div>
<div class="repository">
{{template "repo/header" .}}
<div class="ui container">
{{template "base/alert" .}}
<h4 class="ui top attached header">
{{.i18n.Tr "repo.modelarts.evaluate_job.new_job"}}
</h4>
<div class="ui attached segment">
<!-- equal width -->
<form class="ui form" action="{{.Link}}" method="post">
{{.CsrfTokenHtml}}
<input type="hidden" name="action" value="update">
<div class="required unite min_title inline field">
<label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.job_name"}}</label>
<input style="width: 80%;" name="job_name" id="trainjob_job_name" placeholder={{.i18n.Tr "repo.modelarts.train_job.job_name"}} value="{{.job_name}}" tabindex="3" autofocus required maxlength="254">
</div>
<div class="unite min_title inline field">
<label style="font-weight: normal;" for="description">{{.i18n.Tr "repo.modelarts.train_job.description"}}&nbsp;&nbsp;</label>
<textarea style="width: 80%;" id="description" name="description" rows="3" maxlength="254" placeholder={{.i18n.Tr "repo.modelarts.train_job.new_place"}} onchange="this.value=this.value.substring(0, 255)" onkeydown="this.value=this.value.substring(0, 255)" onkeyup="this.value=this.value.substring(0, 255)"></textarea>
</div>

<div class="required unite min_title inline field">
<label style="font-weight: normal;">GPU类型</label>
<select id="cloudbrain_gpu_type" class="ui search dropdown" placeholder="选择GPU类型" style='width:385px' name="gpu_type">
{{range .benchmark_gpu_types}}
<option value="{{.Queue}}">{{.Value}}</option>
{{end}}
</select>
</div>


<div class="required unite inline min_title fields" style="width: 90%;">
<div class="required eight wide field">
<label style="font-weight: normal;white-space: nowrap;">{{.i18n.Tr "repo.cloudbrain.benchmark.evaluate_type"}}</label>
<span>&nbsp;</span>
<select class="ui fluid selection search dropdown" id="benchmark_types_id" name="benchmark_types_id" >
{{range .benchmark_types}}
<option value="{{.Id}}">{{.First}}</option>
{{end}}
</select>
</div>
<div class="eight wide field" id="engine_name">
<label style="font-weight: normal;white-space: nowrap;">{{.i18n.Tr "repo.cloudbrain.benchmark.evaluate_child_type"}}</label>
<select class="ui fluid selection dropdown nowrap" id="benchmark_child_types_id" style='width: 100%;' name="benchmark_child_types_id">
</select>
</div>
</div>

<div class="required unite min_title inline field">
<label style="font-weight: normal;">{{.i18n.Tr "repo.cloudbrain.benchmark.evaluate_mirror"}}</label>
<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
<input type="text" list="cloudbrain_image" placeholder="选择镜像" name="image" class="required autofocus" style='width:492px;' 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>
{{end}}
{{range .public_images}}
<option name="image" value="{{.Place}}">{{.PlaceView}}</option>
{{end}}
</datalist>
</div>


<div class="required unite min_title inline field">
<label style="font-weight: normal;">资源规格</label>
<select id="cloudbrain_resource_spec" class="ui search dropdown" placeholder="选择资源规格" style='width:385px' name="resource_spec_id">
{{range .benchmark_resource_specs}}
<option name="resource_spec_id" value="{{.Id}}">GPU数:{{.GpuNum}},CPU数:{{.CpuNum}},内存(MB):{{.MemMiB}},共享内存(MB):{{.ShareMemMiB}}</option>
{{end}}
</select>
</div>

<div class="inline unite min_title field required">
<label style="font-weight: normal;">{{.i18n.Tr "repo.cloudbrain.benchmark.evaluate_train"}}</label>
<input disabled="disabled" style="width: 33.5%;" name="train_file" id="train_file" value="train.py" tabindex="3" autofocus required maxlength="254" >
<a href="https://git.openi.org.cn/CV_benchmark/CV_reID_benchmark" target="_blank">查看样例</a>
</div>

<div class="inline unite min_title field required">
<label style="font-weight: normal;">{{.i18n.Tr "repo.cloudbrain.benchmark.evaluate_test"}}</label>
<input disabled="disabled" style="width: 33.5%;" name="test_file" id="test_file" value="test.py" tabindex="3" autofocus required maxlength="254" >
<a href="https://git.openi.org.cn/CV_benchmark/CV_reID_benchmark" target="_blank">查看样例</a>
</div>

<div class="inline unite min_title field">
<button class="ui create_train_job green button">
{{.i18n.Tr "repo.cloudbrain.new"}}
</button>
<a class="ui button" href="/">{{.i18n.Tr "repo.cloudbrain.cancel"}}</a>
</div>
<!-- 模态框 -->
</form>
</div>
</div>
</div>
{{template "base/footer" .}}

<script>
let repolink = {{.RepoLink}}

let url_href = window.location.pathname.split('create')[0]
$(".ui.button").attr('href',url_href)

$('.menu .item')
.tab();

$('#benchmark_types_id').change(function(){
setChildType();
})

function setChildType(){
let type_id = $('#benchmark_types_id').val();
$.get(`${repolink}/cloudbrain/benchmark/get_child_types?benchmark_type_id=${type_id}`, (data) => {
console.log(JSON.stringify(data))
const n_length = data['child_types'].length
let html=''
for (let i=0;i<n_length;i++){
html += `<option value="${data['child_types'][i].id}">${data['child_types'][i].value}</option>`;
}
document.getElementById("benchmark_child_types_id").innerHTML=html;
})
}

document.onreadystatechange = function() {
if (document.readyState === "complete") {
setChildType();
}
}
function validate(){
$('.ui.form')
.form({
on: 'blur',
inline:true,
fields: {
job_name:{
identifier : 'job_name',
rules: [
{
type: 'regExp[/^[a-zA-Z0-9-_]{1,36}$/]',
prompt : '只包含大小写字母、数字、_和-,最长36个字符。'
}
]
},
image:{
identifier : 'image',
rules: [
{
type: 'empty',
prompt : '选择一个镜像'
}
]

}
},
onSuccess: function(){
// $('.ui.page.dimmer').dimmer('show')
document.getElementById("mask").style.display = "block"
},
onFailure: function(e){
return false;
}
})
}


$('.ui.create_train_job.green.button').click(function(e) {
validate()
})
</script>

+ 437
- 0
templates/repo/cloudbrain/benchmark/show.tmpl View File

@@ -0,0 +1,437 @@
{{template "base/head" .}}
<style>
.according-panel-heading{
box-sizing: border-box;
padding: 8px 16px;
color: #252b3a;
background-color: #f2f5fc;
line-height: 1.5;
cursor: pointer;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
-khtml-user-select: none;
user-select: none;
}
.accordion-panel-title {
margin-top: 0;
margin-bottom: 0;
color: #252b3a;
}
.accordion-panel-title-content{
vertical-align: middle;
display: inline-block;
width: calc(100% - 32px);
cursor: default;
}
.acc-margin-bottom {
margin-bottom: 5px;
}
.title_text {
font-size: 12px;
}
.ac-display-inblock {
display: inline-block;
}
.cti-mgRight-sm {
margin-right: 8px;
}
.ac-text-normal {
font-size: 14px;
color: #575d6c;
}
.uc-accordionTitle-black {
color: #333;
}
.accordion-border{
border:1px solid #cce2ff;
}
.padding0{
padding: 0 !important;
}
.content-pad{
padding: 15px 35px;
}
.content-margin{
margin:10px 5px ;
}
.tab_2_content {
min-height: 360px;
margin-left: 10px;
}
.ac-grid {
display: block;
*zoom: 1;
}
.ac-grid-col {
float: left;
width: 100%;
}
.ac-grid-col2 .ac-grid-col {
width: 50%;
}
.ti-form {
text-align: left;
max-width: 100%;
vertical-align: middle;
}
.ti-form>tbody {
font-size: 12px;
}
.ti-form>tbody, .ti-form>tbody>tr {
vertical-align: inherit;
}
.ti-text-form-label {
padding-bottom: 20px;
padding-right: 20px;
color: #8a8e99;
font-size: 12px;
white-space: nowrap !important;
width: 80px;
line-height: 30px;
}
.ti-text-form-content{
line-height: 30px;
padding-bottom: 20px;
}
.ti-form>tbody>tr>td {
vertical-align: top;
white-space: normal;
}
td, th {
padding: 0;
}
.ac-grid-col .text-span {
width: 450px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.redo-color{
color: #3291F8;
}
.ti-action-menu-item:not(:last-child){
margin-right: 10px;
padding-right: 11px;
text-decoration: none!important;
color: #526ecc;
cursor: pointer;
display: inline-block;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
-khtml-user-select: none;
user-select: none;
position: relative;
}
.ti-action-menu-item:not(:last-child):after {
content: "";
display: inline-block;
position: absolute;
height: 12px;
right: 0;
top: 50%;
-webkit-transform: translateY(-6px);
-ms-transform: translateY(-6px);
-o-transform: translateY(-6px);
transform: translateY(-6px);
border-right: 1px solid #dfe1e6;
}
.text-width80{
width: 100px;
line-height: 30px;
}
.border-according{
border: 1px solid #dfe1e6;
}
.disabled {
cursor: default;
pointer-events: none;
color: rgba(0,0,0,.6) !important;
opacity: .45 !important;
}
.pad20{
border:0px !important;
}
.model_file_bread{
margin-bottom: -0.5rem !important;
padding-left: 1rem;
padding-top: 0.5rem ;
}
</style>
<div id="mask">
<div id="loadingPage">
<div class="rect1"></div>
<div class="rect2"></div>
<div class="rect3"></div>
<div class="rect4"></div>
<div class="rect5"></div>
</div>
</div>
<div class="repository">
{{template "repo/header" .}}
<div class="ui container">
<h4 class="ui header" id="vertical-segment">
<div class="ui breadcrumb">
<a class="section" href="{{.RepoLink}}/debugjob?debugListType=all">
{{.i18n.Tr "repo.cloudbrain"}}
</a>
<div class="divider"> / </div>
<a class="section" href="{{$.RepoLink}}/cloudbrain/benchmark">
{{$.i18n.Tr "repo.modelarts.evaluate_job"}}
</a>
<div class="divider"> / </div>
<div class="active section">{{.jobName}}</div>
</div>
</h4>
{{range $k ,$v := .version_list_task}}
<div class="ui accordion border-according" id="accordion{{.VersionName}}" data-repopath="{{$.RepoRelPath}}" data-jobid="{{.JobID}}" data-version="{{.VersionName}}">
<div class="{{if eq $k 0}}active{{end}} title padding0">
<div class="according-panel-heading">
<div class="accordion-panel-title">
<i class="dropdown icon"></i>
<span class="accordion-panel-title-content">
<span>
<div class="ac-display-inblock title_text acc-margin-bottom">
<span class="cti-mgRight-sm">{{TimeSinceUnix1 .CreatedUnix}}</span>
<span class="cti-mgRight-sm">{{$.i18n.Tr "repo.modelarts.status"}}:
<span id="{{.VersionName}}-status-span"><i id="icon" style="vertical-align: middle;" class="{{.Status}}"></i><span id="text" style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span>
</span>
<span class="cti-mgRight-sm">{{$.i18n.Tr "repo.modelarts.train_job.dura_time"}}:</span>
<span class="cti-mgRight-sm uc-accordionTitle-black" id="{{.VersionName}}-duration-span">{{$.duration}}</span>
</div>
</span>
</span>
</div>
</div>
</div>
<div class="{{if eq $k 0}}active{{end}} content">
<div class="content-pad">
<div class="ui pointing secondary menu" style="border-bottom: 1px solid rgba(34,36,38,.15);">
<a class="active item" data-tab="first{{$k}}">{{$.i18n.Tr "repo.modelarts.train_job.config"}}</a>
<a class="item" data-tab="second{{$k}}" onclick="loadLog({{.VersionName}})">{{$.i18n.Tr "repo.modelarts.log"}}</a>
</div>
<div class="ui tab active" data-tab="first{{$k}}">
<div style="padding-top: 10px;">
<div class="tab_2_content">
<div class="ac-grid ac-grid-col2">
<div class="ac-grid-col">
<table class="ti-form">
<tbody class="ti-text-form">
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "repo.cloudbrain_task"}}
</td>
<td class="ti-text-form-content">
<div class="text-span text-span-w">
{{.JobName}}
</div>
</td>
</tr>
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "repo.modelarts.status"}}
</td>

<td class="ti-text-form-content">
<div class="text-span text-span-w" id="{{.VersionName}}-status">
{{.Status}}
</div>
</td>
</tr>
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "repo.modelarts.train_job.start_time"}}
</td>
<td class="ti-text-form-content">
<div class="text-span text-span-w">
<span style="font-size: 12px;" class="">{{TimeSinceUnix1 .CreatedUnix}}</span>
</div>
</td>
</tr>
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "repo.modelarts.train_job.dura_time"}}
</td>
<td class="ti-text-form-content">
<div class="text-span text-span-w" id="{{.VersionName}}-duration">
{{$.duration}}
</div>
</td>
</tr>
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
镜像
</td>
<td class="ti-text-form-content">
<div class="text-span text-span-w" id="{{.VersionName}}-mirror">
{{.Image}}
</div>
</td>
</tr>

</tbody>
</table>
</div>
<div class="ac-grid-col">
<table class="ti-form">
<tbody class="ti-text-form">
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
训练程序
</td>
<td class="ti-text-form-content">
<div class="text-span text-span-w">
train.py
</div>
</td>
</tr>
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
测试程序
</td>
<td class="ti-text-form-content">
<div class="text-span text-span-w">
test.py
</div>
</td>
</tr>
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "repo.modelarts.train_job.description"}}
</td>
<td class="ti-text-form-content">
<div class="text-span text-span-w" title="{{.Description}}">
{{.Description}}
</div>
</td>
</tr>

<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "repo.modelarts.train_job.standard"}}
</td>
<td class="ti-text-form-content">
<div class="text-span text-span-w">
{{$.resource_spec}}
</div>
</td>
</tr>

<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
创建者
</td>
<td class="ti-text-form-content">
<div class="text-span text-span-w" id="{{.VersionName}}-mirror">
{{.User.Name}}
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<div class="ui tab" data-tab="second{{$k}}">
<div>
<div class="ui message message{{.VersionName}}" style="display: none;">
<div id="header"></div>
</div>
<div class="ui attached log" id="log{{.VersionName}}" style="height: 300px !important; overflow: auto;">
<input type="hidden" name="end_line" value>
<input type="hidden" name="start_line" value>
<pre id="log_file{{.VersionName}}"></pre>
</div>
</div>
</div>
</div>
</div>
</div>
{{end}} {{template "base/paginate" .}}
</div>
<!-- 确认模态框 -->
<div id="deletemodel">
<div class="ui basic modal">
<div class="ui icon header">
<i class="trash icon"></i> 删除任务
</div>
<div class="content">
<p>你确认删除该任务么?此任务一旦删除不可恢复。</p>
</div>
<div class="actions">
<div class="ui red basic inverted cancel button">
<i class="remove icon"></i> 取消操作
</div>
<div class="ui green basic inverted ok button">
<i class="checkmark icon"></i> 确定操作
</div>
</div>
</div>
</div>
</div>
{{template "base/footer" .}}

<script>
$('.menu .item').tab()

$(document).ready(function(){
$('.ui.accordion').accordion({selector:{trigger:'.icon'}});
});
$(document).ready(function(){
$('.secondary.menu .item').tab();
});
let userName
let repoPath
let jobID
$(document).ready(function(){
let url = window.location.href;
let urlArr = url.split('/')
userName = urlArr.slice(-5)[0]
repoPath = urlArr.slice(-4)[0]
jobID = urlArr.slice(-1)[0]
})


function loadLog(version_name){
document.getElementById("mask").style.display = "block"
$.get(`/api/v1/repos/${userName}/${repoPath}/cloudbrain/${jobID}/log?version_name=${version_name}&lines=50&order=asc`, (data) => {
$('input[name=end_line]').val(data.EndLine)
$('input[name=start_line]').val(data.StartLine)
$(`#log_file${version_name}`).text(data.Content)
document.getElementById("mask").style.display = "none"
}).fail(function(err) {
console.log(err);
document.getElementById("mask").style.display = "none"
});
}
</script>

+ 1
- 4
templates/repo/cloudbrain/new.tmpl View File

@@ -150,13 +150,10 @@
<input name="job_name" id="cloudbrain_job_name" placeholder="任务名称" value="{{.job_name}}" tabindex="3" autofocus required maxlength="255" onkeyup="this.value=this.value.replace(/[, ]/g,'')">
</div>

<div class="inline required field" style="{{if ((.is_benchmark_enabled) or (.is_snn4imagenet_enabled) or (.is_brainscore_enabled))}}display:block;{{else}}display:none;{{end}}">
<div class="inline required field">
<label>任务类型</label>
<select id="cloudbrain_job_type" class="ui search dropdown" placeholder="选择任务类型" style='width:385px' name="job_type">
<option name="job_type" value="DEBUG">DEBUG</option>
{{if .is_benchmark_enabled}}
<option name="job_type" value="BENCHMARK">BENCHMARK</option>
{{end}}
{{if .is_snn4imagenet_enabled}}
<option name="job_type" value="SNN4IMAGENET">SNN4IMAGENET</option>
{{end}}


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

@@ -218,6 +218,7 @@
<a class="active item" href="{{.RepoLink}}/debugjob?debugListType=all">{{$.i18n.Tr "repo.modelarts.notebook"}}</a>
<a class="item" href="{{.RepoLink}}/modelarts/train-job">{{$.i18n.Tr "repo.modelarts.train_job"}}</a>
<a class="item" href="{{.RepoLink}}/modelarts/inference-job">{{$.i18n.Tr "repo.modelarts.infer_job"}}</a>
<a class="item" href="{{.RepoLink}}/cloudbrain/benchmark">{{$.i18n.Tr "repo.modelarts.evaluate_job"}}</a>
</div>
</div>
<div class="column right aligned">


+ 1
- 1
templates/repo/header.tmpl View File

@@ -90,7 +90,7 @@
{{end}}
<div class="ui tabs container">
{{if not .Repository.IsBeingCreated}}
<div class="ui tabular stackable menu navbar">
<div class="ui tabular menu navbar">
{{if .Permission.CanRead $.UnitTypeCode}}
<div class="dropdown-menu">
<a class="{{if or .PageIsViewCode .PageIsReleaseList .PageIsWiki .PageIsActivity .PageIsViewCode}}active{{end}} item hover_active" href="{{.RepoLink}}{{if (ne .BranchName .Repository.DefaultBranch)}}/src/{{.BranchNameSubURL | EscapePound}}{{end}}">


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

@@ -35,6 +35,7 @@
<a class="item" href="{{.RepoLink}}/debugjob?debugListType=all">{{$.i18n.Tr "repo.modelarts.notebook"}}</a>
<a class="item" href="{{.RepoLink}}/modelarts/train-job">{{$.i18n.Tr "repo.modelarts.train_job"}}</a>
<a class="active item" href="{{.RepoLink}}/modelarts/inference-job">{{$.i18n.Tr "repo.modelarts.infer_job"}}</a>
<a class="item" href="{{.RepoLink}}/cloudbrain/benchmark">{{$.i18n.Tr "repo.modelarts.evaluate_job"}}</a>
</div>
</div>
<div class="column right aligned">


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

@@ -35,6 +35,7 @@
<a class="item" href="{{.RepoLink}}/debugjob?debugListType=all">{{$.i18n.Tr "repo.modelarts.notebook"}}</a>
<a class="active item" href="{{.RepoLink}}/modelarts/train-job">{{$.i18n.Tr "repo.modelarts.train_job"}}</a>
<a class="item" href="{{.RepoLink}}/modelarts/inference-job">{{$.i18n.Tr "repo.modelarts.infer_job"}}</a>
<a class="item" href="{{.RepoLink}}/cloudbrain/benchmark">{{$.i18n.Tr "repo.modelarts.evaluate_job"}}</a>
</div>
</div>
<div class="column right aligned">


+ 104
- 2
web_src/less/openi.less View File

@@ -15,8 +15,8 @@ a {
}
.following.bar #navbar .brand{
padding-left: 0;
padding-top: 0;
padding-bottom: 0;
padding-top: 0;
padding-bottom: 0;
}
.following.bar .brand .ui.mini.image {
width: auto;
@@ -615,4 +615,106 @@ display: block;
}
.a_margin{
margin: 0px !important;
}
@media only screen and (max-width: 767px) {
.following.bar #navbar .brand{
padding-top: 6px;
}
.secondary.menu + .ui.container{
margin-left:0 !important;
margin-right:0 !important;
}
.repo-title{
position: absolute;
top: 6px;
left: 50px;
right: 70px;
height: 40px;
line-height: 40px !important;
text-align: center;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: #FFF;
background-color: #363840;
padding-left: 20px;
}
.repo-title a{
color: #FFF !important;
}
.repo-title img + a{
display: none !important;
}
.repository .header-wrapper{
margin-bottom: 36px;
}
.header-wrapper .tabs.divider{
margin-top: 40px !important;
}
.repository .ui.tabs.container{
margin-top: -60px;
}
.repo-title .divider,
.repo-title svg,
.repo-title img,
.ui.tabular.menu .item svg,
.ui.tabular.menu .item i,
.ui.tabular.menu .item .label,
.ui.tabular.menu .dropdown-content,
.repository.file .repository-summary,
.repository-summary + .menu,
.desc-home .edit-icon,
#repo-files-table .message,
#repo-files-table .age,
#repo-files-table .ui.sha.label,
#repo-files-table .commit-button,
.members
{
display: none !important;
}
.header-wrapper{
display: flex;
flex-direction: column-reverse;
}
.ui.tabular.menu .item{
padding: .5em;
}
.ui.tabular.menu .active.item{
border: none;
background: none;
color: #000000;
border-bottom: 2px solid #000;
white-space: nowrap;
}
.repository .repo-header{
margin-bottom: -50px;
}
.repo-header .repo-buttons{
position: absolute;
right: 15px;
margin-bottom: -60px;
}
.repo-buttons .ui.labeled.button>.button{
box-shadow: none !important;
width: 16px;
overflow: hidden;
white-space: nowrap;
}
.repo-buttons .ui.labeled.button>.label{
border: none !important;
}
.repository.file.list #repo-files-table td.name{
max-width: 100%;
}
#repo-files-table tr{
padding-top: 0;
padding-bottom: 0;
}
.ui.attached:not(.message)+.ui.attached.segment:not(.top){
border: none;
}
.markdown:not(code).file-view{
padding: 2em 0!important;
}
}

Loading…
Cancel
Save