Reviewed-on: https://git.openi.org.cn/OpenI/aiforge/pulls/1405 Reviewed-by: ychao_1983 <ychao_1983@sina.com>tags/v1.22.1.3
| @@ -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 is not exist, %v", err, ctx.Data["MsgID"]) | |||
| cloudBrainNewDataPrepare(ctx) | |||
| ctx.RenderWithErr("train.py is 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 is not exist, %v", err, ctx.Data["MsgID"]) | |||
| cloudBrainNewDataPrepare(ctx) | |||
| ctx.RenderWithErr("test.py is 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;"><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: 80%;' 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">{{.TrainJobDuration}}</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> | |||
| @@ -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"> | |||
| @@ -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"> | |||