@@ -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 | |||
} | |||
@@ -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 { | |||
@@ -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, | |||
} | |||
@@ -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 | |||
} |
@@ -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) | |||
@@ -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 | |||
@@ -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 = 模型文件 | |||
@@ -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() { | |||
@@ -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 | |||
} |
@@ -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" | |||
@@ -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") | |||
} |
@@ -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 { | |||
@@ -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) | |||
@@ -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> |
@@ -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"}} </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> </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> </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> |
@@ -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> |
@@ -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}} | |||
@@ -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"> | |||
@@ -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}}"> | |||
@@ -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"> | |||
@@ -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"> | |||
@@ -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; | |||
} | |||
} |