diff --git a/index.html b/index.html new file mode 100644 index 000000000..643c31b06 --- /dev/null +++ b/index.html @@ -0,0 +1,688 @@ + + + + + + + OpenI + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + +
+ + +
+ + + + + + +
+
+
+

+ Explore Better AI +
+ OpenI AI Development Cooperation Platform +
+

+

The one-stop collaborative development environment for AI field provides AI development pipeline integrating code development, data management, model debugging, reasoning and evaluation

+ + + Use Now + +
+
+
+

* Only show the dynamics of open source projects

+
+
+
+
+ +
+
+
+
+
+ +
+
+ + +
+
+
+

Recommended Organizations

+

These excellent organizations are using the OpenI AI Collaboration Platform for collaborative development of projects. To show your organization here, Click here to submit.

+ More Organizations +
+
+
+
+ +
+
+ +
+
+ +
+

Community Activities

+

The community has prepared a wealth of activities, waiting for you to participate!

+
+
+
+
+ +
+
+
+
+
+ +
+
+ + +
+
+
+
+

Recommended Projects

+

Excellent AI projects recommendation. To show your project here, Click here to submit.Click here to explore more projects.

+
+ +
+
+ +
+
+
+ +
+ +
+
+
+

智算网络

+

人工智能算力网络推进联盟已接入10家智算中心,算力总规模1542P

+
+ +
+ + +
+ +
+ + +
+
+
+
+
+ +

+
+
+
+
+
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+
+
+
+
+
+
+ + +
+ +
+

Collaborative Development Environment

+

Provide a collaborative development environment for AI development, which is the biggest highlight that distinguishes the OpenI AI Collaboration Platform from other traditional Git platforms.

+
+
+
+
+ +
+
+

Unified Management of Development Elements

+
+ The platform provides four elements of AI development: unified management of model code, data set, model and execution environment. +
+
+
+
+
+ +
+
+

Data Collaboration and Sharing

+
+ By uploading data sets in the project, many project members cooperate to complete data preprocessing. You can also establish a better model with community developers by setting the data as a public dataset. +
+
+
+
+
+ +
+
+

Model Management and Sharing

+
+ Associate the model with the code version, you can adjust the model in different ways based on the historical version of the code and save the results. The trained model can be open and shared, so that more people can use the model to test and give feedback. +
+
+
+
+
+ +
+
+

Once Configuration, Multiple Reuse

+
+ Provide execution environment sharing, Once Configuration, Multiple Reuse. Lower the threshold of model development, and avoid spending repetitive time configuring complex environments. +
+
+
+
+
+ + +
+
+
+
+ +
+
+

PengCheng Cloudbrain Open Source Collaboration

+

+ The platform has been connected with Pengcheng Cloudbrain and can use the rich computing resources of Pengcheng Cloudbrain to complete AI development tasks.
+ Pengcheng Cloudbrain's existing AI computing power is 100p FLOPS@FP16 (billions of half precision floating-point calculations per second), the main hardware infrastructure is composed of GPU server equipped with NVIDIA Tesla V100 and Atlas 900 AI cluster equipped with Kunpeng and Ascend processors.
+ Developers can freely choose the corresponding computing resources according to their needs, and can test the adaptability, performance, stability of the model in different hardware environments.
+ If your model requires more computing resources, you can also apply for it separately.
+

+ + + Use Now + + + Apply Separately +
+
+
+
+
+ + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/models/cloudbrain.go b/models/cloudbrain.go index 9e59185eb..2f3156c98 100755 --- a/models/cloudbrain.go +++ b/models/cloudbrain.go @@ -305,6 +305,22 @@ type CreateJobResult struct { Payload map[string]interface{} `json:"payload"` } +type QueueDetailResult struct { + Code string `json:"code"` + Msg string `json:"msg"` + Payload map[string]QueueDetail `json:"payload"` +} + +type QueueDetail struct { + JobScheduleInfo JobScheduleInfo `json:"JobScheduleInfo"` +} + +type JobScheduleInfo struct { + Pending int `json:"Pending"` + Running int `json:"Running"` + MedianPendingJobDurationSec int `json:"MedianPendingJobDurationSec"` +} + type GetJobResult struct { Code string `json:"code"` Msg string `json:"msg"` @@ -1784,6 +1800,17 @@ func GetBenchmarkCountByUserID(userID int64) (int, error) { return int(count), err } +func GetWaitingCloudbrainCount(cloudbrainType int, computeResource string, jobTypes ...JobType) (int64, error) { + sess := x.Where("status=? and type=?", JobWaiting, cloudbrainType) + if len(jobTypes) >= 0 { + sess.In("JobType", jobTypes) + } + if computeResource != "" { + sess.And("compute_resource=?", computeResource) + } + return sess.Count(new(Cloudbrain)) +} + func GetCloudbrainNotebookCountByUserID(userID int64) (int, error) { count, err := x.In("status", ModelArtsCreateQueue, ModelArtsCreating, ModelArtsStarting, ModelArtsReadyToStart, ModelArtsResizing, ModelArtsStartQueuing, ModelArtsRunning, ModelArtsRestarting). And("job_type = ? and user_id = ? and type = ?", JobTypeDebug, userID, TypeCloudBrainTwo).Count(new(Cloudbrain)) diff --git a/modules/auth/cloudbrain.go b/modules/auth/cloudbrain.go index e5be38084..91fa8ad64 100755 --- a/modules/auth/cloudbrain.go +++ b/modules/auth/cloudbrain.go @@ -50,6 +50,27 @@ type EditImageCloudBrainForm struct { Topics string `form:"topics"` } +type CreateCloudBrainInferencForm struct { + JobName string `form:"job_name" binding:"Required"` + DisplayJobName string `form:"display_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"` + BootFile string `form:"boot_file"` + Params string `form:"run_para_list"` + BranchName string `form:"branch_name"` + ModelName string `form:"model_name" binding:"Required"` + ModelVersion string `form:"model_version" binding:"Required"` + CkptName string `form:"ckpt_name" binding:"Required"` +} + func (f *CreateCloudBrainForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { return validate(errs, ctx.Data, f, ctx.Locale) } @@ -61,3 +82,7 @@ func (f *CommitImageCloudBrainForm) Validate(ctx *macaron.Context, errs binding. func (f *EditImageCloudBrainForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { return validate(errs, ctx.Data, f, ctx.Locale) } + +func (f *CreateCloudBrainInferencForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { + return validate(errs, ctx.Data, f, ctx.Locale) +} diff --git a/modules/cloudbrain/cloudbrain.go b/modules/cloudbrain/cloudbrain.go index 5d6948acb..df5045218 100755 --- a/modules/cloudbrain/cloudbrain.go +++ b/modules/cloudbrain/cloudbrain.go @@ -3,6 +3,7 @@ package cloudbrain import ( "encoding/json" "errors" + "os" "strconv" "code.gitea.io/gitea/modules/timeutil" @@ -37,12 +38,15 @@ const ( Success = "S000" DefaultBranchName = "master" + + ResultPath = "/result" ) var ( - ResourceSpecs *models.ResourceSpecs - TrainResourceSpecs *models.ResourceSpecs - SpecialPools *models.SpecialPools + ResourceSpecs *models.ResourceSpecs + TrainResourceSpecs *models.ResourceSpecs + InferenceResourceSpecs *models.ResourceSpecs + SpecialPools *models.SpecialPools ) type GenerateCloudBrainTaskReq struct { @@ -69,6 +73,11 @@ type GenerateCloudBrainTaskReq struct { BenchmarkTypeID int BenchmarkChildTypeID int ResourceSpecId int + ResultPath string + TrainUrl string + ModelName string + ModelVersion string + CkptName string } func GetCloudbrainDebugCommand() string { @@ -219,7 +228,6 @@ func AdminOrImageCreaterRight(ctx *context.Context) { func GenerateTask(req GenerateCloudBrainTaskReq) error { var resourceSpec *models.ResourceSpec var versionCount int - if req.JobType == string(models.JobTypeTrain) { versionCount = 1 if TrainResourceSpecs == nil { @@ -231,6 +239,17 @@ func GenerateTask(req GenerateCloudBrainTaskReq) error { break } } + } else if req.JobType == string(models.JobTypeInference) { + if InferenceResourceSpecs == nil { + json.Unmarshal([]byte(setting.InferenceResourceSpecs), &InferenceResourceSpecs) + } + for _, spec := range InferenceResourceSpecs.ResourceSpec { + if req.ResourceSpecId == spec.Id { + resourceSpec = spec + break + } + } + } else { if ResourceSpecs == nil { json.Unmarshal([]byte(setting.ResourceSpecs), &ResourceSpecs) @@ -245,21 +264,7 @@ func GenerateTask(req GenerateCloudBrainTaskReq) error { } //如果没有匹配到spec信息,尝试从专属资源池获取 if resourceSpec == nil && SpecialPools != nil { - for _, specialPool := range SpecialPools.Pools { - if resourceSpec != nil { - break - } - if specialPool.ResourceSpec != nil { - if IsElementExist(specialPool.JobType, req.JobType) && IsQueueInSpecialtPool(specialPool.Pool, req.GpuQueue) { - for _, spec := range specialPool.ResourceSpec { - if req.ResourceSpecId == spec.Id { - resourceSpec = spec - break - } - } - } - } - } + resourceSpec = geMatchResourceSpec(req.JobType, req.GpuQueue, req.ResourceSpecId) } if resourceSpec == nil { @@ -303,6 +308,13 @@ func GenerateTask(req GenerateCloudBrainTaskReq) error { ReadOnly: true, }, }, + { + HostPath: models.StHostPath{ + Path: req.ResultPath, + MountPath: ResultPath, + ReadOnly: false, + }, + }, } if len(req.DatasetInfos) == 1 { @@ -383,6 +395,11 @@ func GenerateTask(req GenerateCloudBrainTaskReq) error { BootFile: req.BootFile, DatasetName: req.DatasetNames, Parameters: req.Params, + TrainUrl: req.TrainUrl, + ModelName: req.ModelName, + ModelVersion: req.ModelVersion, + CkptName: req.CkptName, + ResultUrl: req.ResultPath, CreatedUnix: createTime, UpdatedUnix: createTime, CommitID: req.CommitID, @@ -403,6 +420,8 @@ func GenerateTask(req GenerateCloudBrainTaskReq) error { notification.NotifyOtherTask(req.Ctx.User, req.Ctx.Repo.Repository, stringId, req.DisplayJobName, models.ActionCreateBenchMarkTask) } else if string(models.JobTypeTrain) == req.JobType { notification.NotifyOtherTask(req.Ctx.User, req.Ctx.Repo.Repository, jobID, req.DisplayJobName, models.ActionCreateGPUTrainTask) + } else if string(models.JobTypeInference) == req.JobType { + notification.NotifyOtherTask(req.Ctx.User, req.Ctx.Repo.Repository, jobID, req.DisplayJobName, models.ActionCreateInferenceTask) } else { notification.NotifyOtherTask(req.Ctx.User, req.Ctx.Repo.Repository, stringId, req.DisplayJobName, models.ActionCreateDebugGPUTask) } @@ -414,6 +433,15 @@ func IsBenchmarkJob(jobType string) bool { return string(models.JobTypeBenchmark) == jobType || string(models.JobTypeBrainScore) == jobType || string(models.JobTypeSnn4imagenet) == jobType } +func GetWaitingCloudbrainCount(cloudbrainType int, computeResource string, jobTypes ...models.JobType) int64 { + num, err := models.GetWaitingCloudbrainCount(cloudbrainType, computeResource, jobTypes...) + if err != nil { + log.Warn("Get waiting count err", err) + num = 0 + } + return num +} + func RestartTask(ctx *context.Context, task *models.Cloudbrain, newID *string) error { jobName := task.JobName @@ -427,6 +455,11 @@ func RestartTask(ctx *context.Context, task *models.Cloudbrain, newID *string) e } } + //如果没有匹配到spec信息,尝试从专属资源池获取 + if resourceSpec == nil && SpecialPools != nil { + resourceSpec = geMatchResourceSpec(task.JobType, task.GpuQueue, task.ResourceSpecId) + } + if resourceSpec == nil { log.Error("no such resourceSpecId(%d)", task.ResourceSpecId, ctx.Data["MsgID"]) return errors.New("no such resourceSpec") @@ -565,6 +598,63 @@ func RestartTask(ctx *context.Context, task *models.Cloudbrain, newID *string) e return nil } +func geMatchResourceSpec(jobType string, gpuQueue string, resourceSpecId int) *models.ResourceSpec { + + for _, specialPool := range SpecialPools.Pools { + + if specialPool.ResourceSpec != nil { + if IsElementExist(specialPool.JobType, jobType) && IsQueueInSpecialtPool(specialPool.Pool, gpuQueue) { + for _, spec := range specialPool.ResourceSpec { + if resourceSpecId == spec.Id { + return spec + } + } + } + } + } + return nil +} + +func DelCloudBrainJob(jobId string) string { + task, err := models.GetCloudbrainByJobID(jobId) + if err != nil { + log.Error("get cloud brain err:", err) + return "cloudbrain.Delete_failed" + + } + 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) + return "cloudbrain.Not_Stopped" + } + + err = models.DeleteJob(task) + if err != nil { + log.Error("DeleteJob failed:", err) + return "cloudbrain.Delete_failed" + } + + deleteJobStorage(task.JobName) + + return "" +} + +func deleteJobStorage(jobName string) error { + //delete local + localJobPath := setting.JobPath + jobName + err := os.RemoveAll(localJobPath) + if err != nil { + log.Error("RemoveAll(%s) failed:%v", localJobPath, err) + } + + dirPath := setting.CBCodePathPrefix + jobName + "/" + err = storage.Attachments.DeleteDir(dirPath) + if err != nil { + log.Error("DeleteDir(%s) failed:%v", localJobPath, err) + } + + return nil +} + func InitSpecialPool() { if SpecialPools == nil && setting.SpecialPools != "" { json.Unmarshal([]byte(setting.SpecialPools), &SpecialPools) diff --git a/modules/cloudbrain/resty.go b/modules/cloudbrain/resty.go index e70dbdd2b..7b714c4b5 100755 --- a/modules/cloudbrain/resty.go +++ b/modules/cloudbrain/resty.go @@ -30,6 +30,7 @@ const ( LogPageSize = 500 LogPageTokenExpired = "5m" pageSize = 15 + QueuesDetailUrl = "/rest-server/api/v2/queuesdetail" ) func getRestyClient() *resty.Client { @@ -73,12 +74,44 @@ func loginCloudbrain() error { return nil } +func GetQueuesDetail() (*map[string]int, error) { + checkSetting() + client := getRestyClient() + var jobResult models.QueueDetailResult + + var result = make(map[string]int, 0) + + res, err := client.R(). + SetHeader("Content-Type", "application/json"). + SetAuthToken(TOKEN). + SetResult(&jobResult). + Get(HOST + QueuesDetailUrl) + + if err != nil { + return nil, fmt.Errorf("resty get queues detail failed: %s", err) + } + + if jobResult.Code != Success { + return nil, fmt.Errorf("jobResult err: %s", res.String()) + } + + for k, v := range jobResult.Payload { + + result[k] = v.JobScheduleInfo.Pending + + } + return &result, nil + +} + func CreateJob(jobName string, createJobParams models.CreateJobParams) (*models.CreateJobResult, error) { checkSetting() client := getRestyClient() var jobResult models.CreateJobResult retry := 0 + reqPara, _ := json.Marshal(createJobParams) + log.Warn("job req:", string(reqPara[:])) sendjob: res, err := client.R(). @@ -143,16 +176,6 @@ sendjob: return &getJobResult, nil } -func GetImages() (*models.GetImagesResult, error) { - - return GetImagesPageable(1, 100, Custom, "") - -} - -func GetPublicImages() (*models.GetImagesResult, error) { - return GetImagesPageable(1, 100, Public, "") -} - func GetImagesPageable(page int, size int, imageType string, name string) (*models.GetImagesResult, error) { checkSetting() client := getRestyClient() diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 003b11569..6ec54fdff 100755 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -463,23 +463,26 @@ var ( DecompressOBSTaskName string //cloudbrain config - CBAuthUser string - CBAuthPassword string - RestServerHost string - JobPath string - CBCodePathPrefix string - JobType string - GpuTypes string - SpecialPools string - DebugServerHost string - ResourceSpecs string - MaxDuration int64 - TrainGpuTypes string - TrainResourceSpecs string - MaxModelSize float64 - MaxDatasetNum int - CullIdleTimeout string - CullInterval string + + CBAuthUser string + CBAuthPassword string + RestServerHost string + JobPath string + CBCodePathPrefix string + JobType string + GpuTypes string + SpecialPools string + DebugServerHost string + ResourceSpecs string + MaxDuration int64 + TrainGpuTypes string + TrainResourceSpecs string + InferenceGpuTypes string + InferenceResourceSpecs string + MaxModelSize float64 + MaxDatasetNum int + CullIdleTimeout string + CullInterval string //benchmark config IsBenchmarkEnabled bool @@ -1347,6 +1350,8 @@ func NewContext() { TrainGpuTypes = sec.Key("TRAIN_GPU_TYPES").MustString("") TrainResourceSpecs = sec.Key("TRAIN_RESOURCE_SPECS").MustString("") MaxModelSize = sec.Key("MAX_MODEL_SIZE").MustFloat64(500) + InferenceGpuTypes = sec.Key("INFERENCE_GPU_TYPES").MustString("") + InferenceResourceSpecs = sec.Key("INFERENCE_RESOURCE_SPECS").MustString("") SpecialPools = sec.Key("SPECIAL_POOL").MustString("") MaxDatasetNum = sec.Key("MAX_DATASET_NUM").MustInt(5) diff --git a/modules/storage/obs.go b/modules/storage/obs.go index bbd40fe65..29b7998f7 100755 --- a/modules/storage/obs.go +++ b/modules/storage/obs.go @@ -645,6 +645,8 @@ func GetObsLogFileName(prefix string) (string, error) { log.Error("PutObject failed:", err.Error()) return "", err } - + if output == nil || len(output.Contents) == 0 { + return "", errors.New("obs log files not exist") + } return output.Contents[0].Key, nil } diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index a6c87529a..b641f4011 100755 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1037,8 +1037,9 @@ image_delete_fail=Failed to delete image, please try again later. image_overwrite=You had submitted the same name image before, are you sure to overwrite the original image? download=Download score=Score +wait_count_start = There are currently +wait_count_end = tasks queued file_limit_100 = Display up to 100 files or folders in a single directory - images.name = Image Tag images.name_placerholder = Please enter the image name image.label_tooltips = Example Python 3.7, Tensorflow 2.0, cuda 10, pytorch 1.6 @@ -3130,4 +3131,10 @@ INFERENCE = INFERENCE BENCHMARK = BENCHMARK brain_area = Brain Area -error.dataset_select = dataset select error:the count exceed the limit or has same name \ No newline at end of file +Delete_failed=Fail to delete the job, please try again later. +Not_Stopped=The job is not stopped, can not be deleted. +Already_stopped=The job is already stopped. +Stopped_failed=Fail to stop the job, please try again later. +Stopped_success_update_status_fail=Succeed in stopping th job, but failed to update the job status and duration time. + +error.dataset_select = dataset select error:the count exceed the limit or has same name diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 976446643..87630d6c0 100755 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -1037,8 +1037,9 @@ image_delete_fail=删除镜像失败,请稍后再试。 image_overwrite=您已经提交过相同名称的镜像,您确定要覆盖原来提交的镜像吗? download=模型下载 score=评分 +wait_count_start = 当前有 +wait_count_end = 个任务正在排队 file_limit_100 = 单目录下最多显示100个文件或文件夹 - images.name = 镜像Tag images.name_placerholder = 请输入镜像Tag image.label_tooltips = 如Python 3.7, Tensorflow 2.0, cuda 10, pytorch 1.6 @@ -3144,4 +3145,11 @@ INFERENCE = 推理任务 BENCHMARK = 评测任务 brain_area = 脑区 -error.dataset_select = 数据集选择错误:数量超过限制或者有同名数据集 \ No newline at end of file +Delete_failed=任务删除失败,请稍后再试。 +Not_Stopped=任务还未终止,不能删除。 +Already_stopped=任务已停止。 +Stopped_failed=任务停止失败,请稍后再试。 +Stopped_success_update_status_fail=任务停止成功,状态及运行时间更新失败。 + + +error.dataset_select = 数据集选择错误:数量超过限制或者有同名数据集 diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 9ba40372b..9a4774fa3 100755 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -922,6 +922,13 @@ func RegisterRoutes(m *macaron.Macaron) { m.Post("/stop_version", cloudbrain.AdminOrOwnerOrJobCreaterRightForTrain, repo_ext.CloudBrainStop) }) }) + m.Group("/inference-job", func() { + m.Group("/:jobid", func() { + m.Get("", repo.GetCloudBrainInferenceJob) + m.Post("/del", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.DelCloudBrainJob) + m.Get("/result_list", repo.InferencJobResultList) + }) + }) }, reqRepoReader(models.UnitTypeCloudBrain)) m.Group("/modelmanage", func() { m.Get("/:id", repo.GetCloudbrainModelConvertTask) diff --git a/routers/api/v1/repo/cloudbrain.go b/routers/api/v1/repo/cloudbrain.go index c21bd2bf5..5ebbc9b46 100755 --- a/routers/api/v1/repo/cloudbrain.go +++ b/routers/api/v1/repo/cloudbrain.go @@ -6,13 +6,14 @@ package repo import ( - "code.gitea.io/gitea/modules/setting" "encoding/json" "net/http" "sort" "strings" "time" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/cloudbrain" "code.gitea.io/gitea/modules/context" @@ -102,11 +103,126 @@ func GetCloudbrainTask(ctx *context.APIContext) { } +func GetCloudBrainInferenceJob(ctx *context.APIContext) { + + jobID := ctx.Params(":jobid") + job, err := models.GetCloudbrainByJobID(jobID) + if err != nil { + ctx.NotFound(err) + return + } + jobResult, err := cloudbrain.GetJob(job.JobID) + if err != nil { + ctx.NotFound(err) + log.Error("GetJob failed:", err) + return + } + result, err := models.ConvertToJobResultPayload(jobResult.Payload) + if err != nil { + ctx.NotFound(err) + log.Error("ConvertToJobResultPayload failed:", err) + return + } + + job.Status = result.JobStatus.State + if result.JobStatus.State != string(models.JobWaiting) && result.JobStatus.State != string(models.JobFailed) { + taskRoles := result.TaskRoles + taskRes, _ := models.ConvertToTaskPod(taskRoles[cloudbrain.SubTaskName].(map[string]interface{})) + + job.ContainerIp = taskRes.TaskStatuses[0].ContainerIP + job.ContainerID = taskRes.TaskStatuses[0].ContainerID + job.Status = taskRes.TaskStatuses[0].State + } + + if result.JobStatus.State != string(models.JobWaiting) { + models.ParseAndSetDurationFromCloudBrainOne(result, job) + err = models.UpdateJob(job) + if err != nil { + log.Error("UpdateJob failed:", err) + } + } + + ctx.JSON(http.StatusOK, map[string]interface{}{ + "JobID": jobID, + "JobStatus": job.Status, + "JobDuration": job.TrainJobDuration, + }) + +} + +func DelCloudBrainJob(ctx *context.APIContext) { + jobID := ctx.Params(":jobid") + + errStr := cloudbrain.DelCloudBrainJob(jobID) + + if errStr != "" { + ctx.JSON(http.StatusOK, map[string]interface{}{ + "message": ctx.Tr(errStr), + "VersionName": "1", + "code": 1, + }) + } else { + ctx.JSON(http.StatusOK, map[string]interface{}{ + "message": "", + "VersionName": "1", + "code": 0, + }) + } + +} + +func InferencJobResultList(ctx *context.APIContext) { + jobID := ctx.Params(":jobid") + parentDir := ctx.Query("parentDir") + dirArray := strings.Split(parentDir, "/") + + task, err := models.GetCloudbrainByJobID(jobID) + if err != nil { + log.Error("get cloud brain err:", err) + ctx.ServerError("get cloud brain information failed:", err) + + } + + //get dirs + dirs, err := routerRepo.GetResultDirs(task.JobName, parentDir) + if err != nil { + log.Error("GetModelDirs failed:%v", err.Error(), ctx.Data["msgID"]) + ctx.ServerError("GetModelDirs failed:", err) + return + } + + var fileInfos []storage.FileInfo + err = json.Unmarshal([]byte(dirs), &fileInfos) + if err != nil { + log.Error("json.Unmarshal failed:%v", err.Error(), ctx.Data["msgID"]) + ctx.ServerError("json.Unmarshal failed:", err) + return + } + + for i, fileInfo := range fileInfos { + temp, _ := time.Parse("2006-01-02 15:04:05", fileInfo.ModTime) + fileInfos[i].ModTime = temp.Local().Format("2006-01-02 15:04:05") + } + + sort.Slice(fileInfos, func(i, j int) bool { + return fileInfos[i].ModTime > fileInfos[j].ModTime + }) + + ctx.JSON(http.StatusOK, map[string]interface{}{ + "JobID": jobID, + "StatusOK": 0, + "Path": dirArray, + "Dirs": fileInfos, + "task": task, + "PageIsCloudBrain": true, + }) + +} + func GetCloudbrainModelConvertTask(ctx *context.APIContext) { var ( err error ) - ID := ctx.Params(":id") job, err := models.QueryModelConvertById(ID) if err != nil { @@ -407,7 +523,9 @@ func GetNewestJobs(ctx *context.APIContext) { ids := make([]int64, len(idsC2Net), cap(idsC2Net)*2) copy(ids, idsC2Net) - copy(ids, idsCloudbrain) + for _, id := range idsCloudbrain { + ids = append(ids, id) + } jobs, err := models.GetCloudbrainByIDs(ids) if err != nil { diff --git a/routers/repo/ai_model_manage.go b/routers/repo/ai_model_manage.go index 5f66cb511..0aef1a70c 100644 --- a/routers/repo/ai_model_manage.go +++ b/routers/repo/ai_model_manage.go @@ -833,7 +833,7 @@ func QueryModelListForPredict(ctx *context.Context) { PageSize: -1, }, RepoID: repoId, - Type: -1, + Type: ctx.QueryInt("type"), New: -1, }) if err != nil { diff --git a/routers/repo/cloudbrain.go b/routers/repo/cloudbrain.go index 4eb810d21..20a1fcc07 100755 --- a/routers/repo/cloudbrain.go +++ b/routers/repo/cloudbrain.go @@ -47,6 +47,9 @@ const ( tplCloudBrainTrainJobNew base.TplName = "repo/cloudbrain/trainjob/new" tplCloudBrainTrainJobShow base.TplName = "repo/cloudbrain/trainjob/show" + + tplCloudBrainInferenceJobNew base.TplName = "repo/cloudbrain/inference/new" + tplCloudBrainInferenceJobShow base.TplName = "repo/cloudbrain/inference/show" ) var ( @@ -56,6 +59,7 @@ var ( benchmarkGpuInfos *models.GpuInfos benchmarkResourceSpecs *models.ResourceSpecs trainGpuInfos *models.GpuInfos + inferenceGpuInfos *models.GpuInfos ) const BENCHMARK_TYPE_CODE = "repo.cloudbrain.benchmark.types" @@ -97,45 +101,6 @@ func cloudBrainNewDataPrepare(ctx *context.Context) error { var displayJobName = jobNamePrefixValid(cutString(ctx.User.Name, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:] ctx.Data["display_job_name"] = displayJobName - result, err := cloudbrain.GetImages() - if err != nil { - ctx.Data["error"] = err.Error() - log.Error("cloudbrain.GetImages failed:", err.Error(), ctx.Data["MsgID"]) - } - - for i, payload := range result.Payload.ImageInfo { - if strings.HasPrefix(result.Payload.ImageInfo[i].Place, "192.168") { - result.Payload.ImageInfo[i].PlaceView = payload.Place[strings.Index(payload.Place, "/"):len(payload.Place)] - } else { - result.Payload.ImageInfo[i].PlaceView = payload.Place - } - } - - ctx.Data["images"] = result.Payload.ImageInfo - - resultPublic, err := cloudbrain.GetPublicImages() - if err != nil { - ctx.Data["error"] = err.Error() - log.Error("cloudbrain.GetPublicImages failed:", err.Error(), ctx.Data["MsgID"]) - } - - for i, payload := range resultPublic.Payload.ImageInfo { - if strings.HasPrefix(resultPublic.Payload.ImageInfo[i].Place, "192.168") { - resultPublic.Payload.ImageInfo[i].PlaceView = payload.Place[strings.Index(payload.Place, "/"):len(payload.Place)] - } else { - resultPublic.Payload.ImageInfo[i].PlaceView = payload.Place - } - } - - ctx.Data["public_images"] = resultPublic.Payload.ImageInfo - - attachs, err := models.GetAllUserAttachments(ctx.User.ID) - if err != nil { - log.Error("GetAllUserAttachments failed: %v", err, ctx.Data["MsgID"]) - return err - } - - ctx.Data["attachments"] = attachs ctx.Data["command"] = cloudbrain.GetCloudbrainDebugCommand() ctx.Data["code_path"] = cloudbrain.CodeMountPath ctx.Data["dataset_path"] = cloudbrain.DataSetMountPath @@ -149,6 +114,10 @@ func cloudBrainNewDataPrepare(ctx *context.Context) error { ctx.Data["benchmark_categories"] = categories.Category ctx.Data["benchmark_types"] = GetBenchmarkTypes(ctx).BenchmarkType + queuesDetail, _ := cloudbrain.GetQueuesDetail() + if queuesDetail != nil { + ctx.Data["QueuesDetail"] = queuesDetail + } cloudbrain.InitSpecialPool() @@ -162,6 +131,11 @@ func cloudBrainNewDataPrepare(ctx *context.Context) error { } ctx.Data["train_gpu_types"] = trainGpuInfos.GpuInfo + if inferenceGpuInfos == nil { + json.Unmarshal([]byte(setting.InferenceGpuTypes), &inferenceGpuInfos) + } + ctx.Data["inference_gpu_types"] = inferenceGpuInfos.GpuInfo + if benchmarkGpuInfos == nil { json.Unmarshal([]byte(setting.BenchmarkGpuTypes), &benchmarkGpuInfos) } @@ -182,6 +156,11 @@ func cloudBrainNewDataPrepare(ctx *context.Context) error { } ctx.Data["train_resource_specs"] = cloudbrain.TrainResourceSpecs.ResourceSpec + if cloudbrain.InferenceResourceSpecs == nil { + json.Unmarshal([]byte(setting.InferenceResourceSpecs), &cloudbrain.InferenceResourceSpecs) + } + ctx.Data["inference_resource_specs"] = cloudbrain.InferenceResourceSpecs.ResourceSpec + if cloudbrain.SpecialPools != nil { var debugGpuTypes []*models.GpuInfo var trainGpuTypes []*models.GpuInfo @@ -372,6 +351,7 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { BenchmarkTypeID: 0, BenchmarkChildTypeID: 0, ResourceSpecId: resourceSpecId, + ResultPath: storage.GetMinioPath(jobName, cloudbrain.ResultPath+"/"), } err = cloudbrain.GenerateTask(req) @@ -388,6 +368,125 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { } } + +func CloudBrainInferenceJobCreate(ctx *context.Context, form auth.CreateCloudBrainInferencForm) { + ctx.Data["PageIsCloudBrain"] = true + displayJobName := form.DisplayJobName + jobName := util.ConvertDisplayJobNameToJobName(displayJobName) + image := strings.TrimSpace(form.Image) + uuid := form.Attachment + jobType := string(models.JobTypeInference) + gpuQueue := form.GpuType + codePath := setting.JobPath + jobName + cloudbrain.CodeMountPath + resourceSpecId := form.ResourceSpecId + branchName := form.BranchName + repo := ctx.Repo.Repository + + ckptUrl := setting.Attachment.Minio.RealPath + form.TrainUrl + form.CkptName + log.Info("ckpt url:" + ckptUrl) + tpl := tplCloudBrainInferenceJobNew + command, err := getInferenceJobCommand(form) + if err != nil { + log.Error("getTrainJobCommand failed: %v", err) + ctx.RenderWithErr(err.Error(), tpl, &form) + return + } + + tasks, err := models.GetCloudbrainsByDisplayJobName(repo.ID, jobType, displayJobName) + if err == nil { + if len(tasks) != 0 { + log.Error("the job name did already exist", ctx.Data["MsgID"]) + cloudBrainNewDataPrepare(ctx) + ctx.RenderWithErr("the job name did already exist", tpl, &form) + return + } + } else { + if !models.IsErrJobNotExist(err) { + log.Error("system error, %v", err, ctx.Data["MsgID"]) + cloudBrainNewDataPrepare(ctx) + ctx.RenderWithErr("system error", tpl, &form) + return + } + } + + if !jobNamePattern.MatchString(displayJobName) { + ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_jobname_err"), tpl, &form) + return + } + + count, err := models.GetCloudbrainCountByUserID(ctx.User.ID, jobType) + if err != nil { + log.Error("GetCloudbrainCountByUserID failed:%v", err, ctx.Data["MsgID"]) + cloudBrainNewDataPrepare(ctx) + ctx.RenderWithErr("system error", tpl, &form) + return + } else { + if count >= 1 { + log.Error("the user already has running or waiting task", ctx.Data["MsgID"]) + cloudBrainNewDataPrepare(ctx) + ctx.RenderWithErr(ctx.Tr("repo.cloudbrain.morethanonejob"), tpl, &form) + return + } + } + + if branchName == "" { + branchName = cloudbrain.DefaultBranchName + } + downloadCode(repo, codePath, branchName) + uploadCodeToMinio(codePath+"/", jobName, cloudbrain.CodeMountPath+"/") + resultPath := setting.JobPath + jobName + cloudbrain.ResultPath + "/" + mkResultPath(resultPath) + uploadCodeToMinio(resultPath, jobName, cloudbrain.ResultPath+"/") + + commitID, _ := ctx.Repo.GitRepo.GetBranchCommitID(branchName) + + datasetInfos, datasetNames, err := models.GetDatasetInfo(uuid) + if err != nil { + log.Error("GetDatasetInfo failed: %v", err, ctx.Data["MsgID"]) + cloudBrainNewDataPrepare(ctx) + ctx.RenderWithErr(ctx.Tr("cloudbrain.error.dataset_select"), tpl, &form) + return + } + + req := cloudbrain.GenerateCloudBrainTaskReq{ + Ctx: ctx, + DisplayJobName: displayJobName, + JobName: jobName, + Image: image, + Command: command, + Uuids: uuid, + DatasetNames: datasetNames, + DatasetInfos: datasetInfos, + CodePath: storage.GetMinioPath(jobName, cloudbrain.CodeMountPath+"/"), + ModelPath: setting.Attachment.Minio.RealPath + form.TrainUrl, + BenchmarkPath: storage.GetMinioPath(jobName, cloudbrain.BenchMarkMountPath+"/"), + Snn4ImageNetPath: storage.GetMinioPath(jobName, cloudbrain.Snn4imagenetMountPath+"/"), + BrainScorePath: storage.GetMinioPath(jobName, cloudbrain.BrainScoreMountPath+"/"), + JobType: jobType, + GpuQueue: gpuQueue, + Description: form.Description, + BranchName: branchName, + BootFile: form.BootFile, + Params: form.Params, + CommitID: commitID, + ResourceSpecId: resourceSpecId, + ResultPath: storage.GetMinioPath(jobName, cloudbrain.ResultPath+"/"), + ModelName: form.ModelName, + ModelVersion: form.ModelVersion, + CkptName: form.CkptName, + TrainUrl: form.TrainUrl, + } + + err = cloudbrain.GenerateTask(req) + if err != nil { + cloudBrainNewDataPrepare(ctx) + ctx.RenderWithErr(err.Error(), tpl, &form) + return + } + + ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/inference-job") + +} /** 检查用户传输的参数是否符合专属资源池 */ @@ -459,7 +558,18 @@ func CloudBrainRestart(ctx *context.Context) { for _, resourceType := range gpuInfos.GpuInfo { if resourceType.Queue == task.GpuQueue { hasSameResource = true - continue + break + } + } + if !hasSameResource && cloudbrain.SpecialPools != nil { + + for _, specialPool := range cloudbrain.SpecialPools.Pools { + cloudbrain.IsElementExist(specialPool.JobType, string(models.JobTypeDebug)) + for _, pool := range specialPool.Pool { + if pool.Queue == task.GpuQueue { + hasSameResource = true + } + } } } @@ -522,7 +632,7 @@ func cloudBrainShow(ctx *context.Context, tpName base.TplName, jobType models.Jo var task *models.Cloudbrain var err error - if jobType == models.JobTypeTrain { + if jobType == models.JobTypeTrain || jobType == models.JobTypeInference { task, err = models.GetCloudbrainByJobID(ctx.Params(":jobid")) } else { task, err = models.GetCloudbrainByIDWithDeleted(ctx.Params(":id")) @@ -553,6 +663,18 @@ func cloudBrainShow(ctx *context.Context, tpName base.TplName, jobType models.Jo ctx.Data["ShareMemMiB"] = tmp.ShareMemMiB } } + } else if task.JobType == string(models.JobTypeInference) { + if cloudbrain.InferenceResourceSpecs == nil { + json.Unmarshal([]byte(setting.InferenceResourceSpecs), &cloudbrain.InferenceResourceSpecs) + } + for _, tmp := range cloudbrain.InferenceResourceSpecs.ResourceSpec { + if tmp.Id == task.ResourceSpecId { + ctx.Data["GpuNum"] = tmp.GpuNum + ctx.Data["CpuNum"] = tmp.CpuNum + ctx.Data["MemMiB"] = tmp.MemMiB + ctx.Data["ShareMemMiB"] = tmp.ShareMemMiB + } + } } else { if cloudbrain.ResourceSpecs == nil { json.Unmarshal([]byte(setting.ResourceSpecs), &cloudbrain.ResourceSpecs) @@ -581,6 +703,15 @@ func cloudBrainShow(ctx *context.Context, tpName base.TplName, jobType models.Jo ctx.Data["resource_type"] = resourceType.Value } } + } else if task.JobType == string(models.JobTypeInference) { + if inferenceGpuInfos == nil { + json.Unmarshal([]byte(setting.InferenceGpuTypes), &inferenceGpuInfos) + } + for _, resourceType := range inferenceGpuInfos.GpuInfo { + if resourceType.Queue == jobRes.Config.GpuType { + ctx.Data["resource_type"] = resourceType.Value + } + } } else if cloudbrain.IsBenchmarkJob(task.JobType) { if benchmarkGpuInfos == nil { json.Unmarshal([]byte(setting.BenchmarkGpuTypes), &benchmarkGpuInfos) @@ -938,7 +1069,7 @@ func CloudBrainStop(ctx *context.Context) { 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" + errorMsg = "cloudbrain.Already_stopped" break } @@ -946,7 +1077,7 @@ func CloudBrainStop(ctx *context.Context) { if err != nil { log.Error("StopJob(%s) failed:%v", task.JobName, err, ctx.Data["msgID"]) resultCode = "-1" - errorMsg = "system error" + errorMsg = "cloudbrain.Stopped_failed" break } @@ -959,7 +1090,7 @@ func CloudBrainStop(ctx *context.Context) { if err != nil { log.Error("UpdateJob(%s) failed:%v", task.JobName, err, ctx.Data["msgID"]) resultCode = "-1" - errorMsg = "system error" + errorMsg = "cloudbrain.Stopped_success_update_status_fail" break } @@ -969,7 +1100,7 @@ func CloudBrainStop(ctx *context.Context) { ctx.JSON(200, map[string]interface{}{ "result_code": resultCode, - "error_msg": errorMsg, + "error_msg": ctx.Tr(errorMsg), "status": status, "id": ID, "StatusOK": 0, @@ -1259,6 +1390,18 @@ func GetModelDirs(jobName string, parentDir string) (string, error) { return getDirs(req) } +func GetResultDirs(jobName string, parentDir string) (string, error) { + var req string + modelActualPath := storage.GetMinioPath(jobName, cloudbrain.ResultPath+"/") + if parentDir == "" { + req = "baseDir=" + modelActualPath + } else { + req = "baseDir=" + modelActualPath + "&parentDir=" + parentDir + } + + return getDirs(req) +} + func CloudBrainDownloadModel(ctx *context.Context) { parentDir := ctx.Query("parentDir") fileName := ctx.Query("fileName") @@ -1273,6 +1416,20 @@ func CloudBrainDownloadModel(ctx *context.Context) { ctx.Resp.Header().Set("Cache-Control", "max-age=0") http.Redirect(ctx.Resp, ctx.Req.Request, url, http.StatusMovedPermanently) } +func CloudBrainDownloadInferenceResult(ctx *context.Context) { + parentDir := ctx.Query("parentDir") + fileName := ctx.Query("fileName") + jobName := ctx.Query("jobName") + filePath := "jobs/" + jobName + "/result/" + parentDir + url, err := storage.Attachments.PresignedGetURL(filePath, fileName) + if err != nil { + log.Error("PresignedGetURL failed: %v", err.Error(), ctx.Data["msgID"]) + ctx.ServerError("PresignedGetURL", err) + return + } + ctx.Resp.Header().Set("Cache-Control", "max-age=0") + http.Redirect(ctx.Resp, ctx.Req.Request, url, http.StatusMovedPermanently) +} func GetRate(ctx *context.Context) { isObjectDetcionAll := ctx.QueryBool("isObjectDetcionAll") @@ -1426,13 +1583,21 @@ func uploadCodeToMinio(codePath, jobName, parentDir string) error { } func mkModelPath(modelPath string) error { - err := os.MkdirAll(modelPath, os.ModePerm) + return mkPathAndReadMeFile(modelPath, "You can put the model file into this directory and download it by the web page.") +} + +func mkResultPath(resultPath string) error { + return mkPathAndReadMeFile(resultPath, "You can put the result file into this directory and download it by the web page.") +} + +func mkPathAndReadMeFile(path string, text string) error { + err := os.MkdirAll(path, os.ModePerm) if err != nil { - log.Error("MkdirAll(%s) failed:%v", modelPath, err) + log.Error("MkdirAll(%s) failed:%v", path, err) return err } - fileName := modelPath + "README" + fileName := path + "README" f, err := os.OpenFile(fileName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.ModePerm) if err != nil { log.Error("OpenFile failed", err.Error()) @@ -1441,7 +1606,7 @@ func mkModelPath(modelPath string) error { defer f.Close() - _, err = f.WriteString("You can put the model file into this directory and download it by the web page.") + _, err = f.WriteString(text) if err != nil { log.Error("WriteString failed", err.Error()) return err @@ -2160,6 +2325,7 @@ func BenchMarkAlgorithmCreate(ctx *context.Context, form auth.CreateCloudBrainFo BenchmarkTypeID: benchmarkTypeID, BenchmarkChildTypeID: benchmarkChildTypeID, ResourceSpecId: resourceSpecId, + ResultPath: storage.GetMinioPath(jobName, cloudbrain.ResultPath+"/"), } err = cloudbrain.GenerateTask(req) @@ -2288,6 +2454,7 @@ func ModelBenchmarkCreate(ctx *context.Context, form auth.CreateCloudBrainForm) BenchmarkTypeID: 0, BenchmarkChildTypeID: benchmarkChildTypeID, ResourceSpecId: resourceSpecId, + ResultPath: storage.GetMinioPath(jobName, cloudbrain.ResultPath+"/"), } err = cloudbrain.GenerateTask(req) @@ -2338,6 +2505,64 @@ func CloudBrainTrainJobNew(ctx *context.Context) { ctx.HTML(http.StatusOK, tplCloudBrainTrainJobNew) } +func InferenceCloudBrainJobNew(ctx *context.Context) { + err := cloudBrainNewDataPrepare(ctx) + if err != nil { + ctx.ServerError("get new train-job info failed", err) + return + } + ctx.HTML(http.StatusOK, tplCloudBrainInferenceJobNew) +} + +func InferenceCloudBrainJobShow(ctx *context.Context) { + cloudBrainShow(ctx, tplCloudBrainInferenceJobShow, models.JobTypeInference) +} + +func DownloadInferenceResultFile(ctx *context.Context) { + var jobID = ctx.Params(":jobid") + var versionName = ctx.Query("version_name") + task, err := models.GetCloudbrainByJobIDAndVersionName(jobID, versionName) + if err != nil { + log.Error("GetCloudbrainByJobID(%s) failed:%v", task.JobName, err.Error()) + return + } + + allFile, err := storage.GetAllObjectByBucketAndPrefixMinio(setting.Attachment.Minio.Bucket, task.ResultUrl) + returnFileName := task.DisplayJobName + ".zip" + MinioDownloadManyFile(task.ResultUrl, ctx, returnFileName, allFile) +} + +func getInferenceJobCommand(form auth.CreateCloudBrainInferencForm) (string, error) { + var command string + bootFile := strings.TrimSpace(form.BootFile) + params := form.Params + + if !strings.HasSuffix(bootFile, ".py") { + log.Error("bootFile(%s) format error", bootFile) + return command, errors.New("bootFile format error") + } + + var parameters models.Parameters + var param string + if len(params) != 0 { + err := json.Unmarshal([]byte(params), ¶meters) + if err != nil { + log.Error("Failed to Unmarshal params: %s (%v)", params, err) + return command, err + } + + for _, parameter := range parameters.Parameter { + param += " --" + parameter.Label + "=" + parameter.Value + } + } + + param += " --modelname" + "=" + form.CkptName + + command += "python /code/" + bootFile + param + " > " + cloudbrain.ResultPath + "/" + form.DisplayJobName + "-" + cloudbrain.LogFile + + return command, nil +} + func getTrainJobCommand(form auth.CreateCloudBrainForm) (string, error) { var command string bootFile := strings.TrimSpace(form.BootFile) diff --git a/routers/repo/grampus.go b/routers/repo/grampus.go index 2e084b535..978b7462d 100755 --- a/routers/repo/grampus.go +++ b/routers/repo/grampus.go @@ -43,6 +43,8 @@ func GrampusTrainJobGPUNew(ctx *context.Context) { ctx.ServerError("get new train-job info failed", err) return } + waitCount := cloudbrain.GetWaitingCloudbrainCount(models.TypeC2Net, models.GPUResource, models.JobTypeTrain) + ctx.Data["WaitCount"] = waitCount ctx.HTML(http.StatusOK, tplGrampusTrainJobGPUNew) } @@ -53,6 +55,8 @@ func GrampusTrainJobNPUNew(ctx *context.Context) { ctx.ServerError("get new train-job info failed", err) return } + waitCount := cloudbrain.GetWaitingCloudbrainCount(models.TypeC2Net, models.NPUResource, models.JobTypeTrain) + ctx.Data["WaitCount"] = waitCount ctx.HTML(200, tplGrampusTrainJobNPUNew) } diff --git a/routers/repo/modelarts.go b/routers/repo/modelarts.go index ecc94a92e..188bd5c6c 100755 --- a/routers/repo/modelarts.go +++ b/routers/repo/modelarts.go @@ -119,7 +119,8 @@ func MustEnableModelArts(ctx *context.Context) { func NotebookNew(ctx *context.Context) { notebookNewDataPrepare(ctx) - + waitCount := cloudbrain.GetWaitingCloudbrainCount(models.TypeCloudBrainTwo, "") + ctx.Data["WaitCount"] = waitCount ctx.HTML(200, tplModelArtsNotebookNew) } @@ -630,6 +631,8 @@ func TrainJobNew(ctx *context.Context) { ctx.ServerError("get new train-job info failed", err) return } + waitCount := cloudbrain.GetWaitingCloudbrainCount(models.TypeCloudBrainTwo, "") + ctx.Data["WaitCount"] = waitCount ctx.HTML(200, tplModelArtsTrainJobNew) } @@ -782,6 +785,8 @@ func TrainJobNewVersion(ctx *context.Context) { ctx.ServerError("get new train-job info failed", err) return } + waitCount := cloudbrain.GetWaitingCloudbrainCount(models.TypeCloudBrainTwo, "") + ctx.Data["WaitCount"] = waitCount ctx.HTML(200, tplModelArtsTrainJobVersionNew) } @@ -1906,8 +1911,8 @@ func InferenceJobCreate(ctx *context.Context, form auth.CreateModelArtsInference modelName := form.ModelName modelVersion := form.ModelVersion ckptName := form.CkptName - - ckptUrl := form.TrainUrl + form.CkptName + ckptUrl := "/" + form.TrainUrl + form.CkptName + log.Info("ckpt url:" + ckptUrl) count, err := models.GetCloudbrainInferenceJobCountByUserID(ctx.User.ID) if err != nil { @@ -2074,6 +2079,13 @@ func InferenceJobIndex(ctx *context.Context) { page = 1 } + listType := ctx.Query("listType") + ctx.Data["ListType"] = listType + + if listType == models.AllResource { + listType = "" + } + var jobTypes []string jobTypes = append(jobTypes, string(models.JobTypeInference)) tasks, count, err := models.Cloudbrains(&models.CloudbrainsOptions{ @@ -2081,9 +2093,10 @@ func InferenceJobIndex(ctx *context.Context) { Page: page, PageSize: setting.UI.IssuePagingNum, }, - RepoID: repo.ID, - Type: models.TypeCloudBrainTwo, - JobTypes: jobTypes, + RepoID: repo.ID, + ComputeResource: listType, + JobTypes: jobTypes, + Type: models.TypeCloudBrainAll, }) if err != nil { ctx.ServerError("Cloudbrain", err) @@ -2093,7 +2106,9 @@ func InferenceJobIndex(ctx *context.Context) { for i, task := range tasks { tasks[i].CanDel = cloudbrain.CanDeleteJob(ctx, &task.Cloudbrain) tasks[i].CanModify = cloudbrain.CanModifyJob(ctx, &task.Cloudbrain) - tasks[i].ComputeResource = models.NPUResource + if tasks[i].ComputeResource == "" { + tasks[i].ComputeResource = models.NPUResource + } } repoId := ctx.Repo.Repository.ID @@ -2125,6 +2140,8 @@ func InferenceJobNew(ctx *context.Context) { ctx.ServerError("get new inference-job info failed", err) return } + waitCount := cloudbrain.GetWaitingCloudbrainCount(models.TypeCloudBrainTwo, "") + ctx.Data["WaitCount"] = waitCount ctx.HTML(200, tplModelArtsInferenceJobNew) } func inferenceJobNewDataPrepare(ctx *context.Context) error { diff --git a/routers/routes/routes.go b/routers/routes/routes.go index 42a3b4e47..35a26f585 100755 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -1105,6 +1105,16 @@ func RegisterRoutes(m *macaron.Macaron) { m.Get("/create", reqWechatBind, reqRepoCloudBrainWriter, repo.CloudBrainTrainJobNew) m.Post("/create", reqWechatBind, reqRepoCloudBrainWriter, bindIgnErr(auth.CreateCloudBrainForm{}), repo.CloudBrainCreate) }) + m.Group("/inference-job", func() { + m.Group("/:jobid", func() { + m.Get("", reqRepoCloudBrainReader, repo.InferenceCloudBrainJobShow) + m.Get("/result_download", cloudbrain.AdminOrJobCreaterRightForTrain, repo.CloudBrainDownloadInferenceResult) + + m.Get("/downloadall", repo.DownloadInferenceResultFile) + }) + m.Get("/create", reqWechatBind, reqRepoCloudBrainWriter, repo.InferenceCloudBrainJobNew) + m.Post("/create", reqWechatBind, reqRepoCloudBrainWriter, bindIgnErr(auth.CreateCloudBrainInferencForm{}), repo.CloudBrainInferenceJobCreate) + }) }, context.RepoRef()) m.Group("/grampus", func() { m.Group("/train-job", func() { diff --git a/templates/admin/cloudbrain/list.tmpl b/templates/admin/cloudbrain/list.tmpl index 347b5658d..e66f40e84 100755 --- a/templates/admin/cloudbrain/list.tmpl +++ b/templates/admin/cloudbrain/list.tmpl @@ -204,7 +204,7 @@ {{else}} {{$.i18n.Tr "repo.stop"}} @@ -212,7 +212,7 @@
{{$.CsrfTokenHtml}}
- {{if or (.benchmarkMode) (.newInference)}} + + {{if .benchmarkMode}}{{.i18n.Tr "repo.modelarts.infer_job.select_model"}}{{else}}{{.i18n.Tr "dataset.select_dataset"}}{{end}} {{if .benchmarkMode}} - 说明:先使用数据集功能上传模型,然后从数据集列表选模型。 + 说明:先使用数据集功能上传模型,然后从数据集列表选模型。 {{end}}
diff --git a/templates/custom/wait_count.tmpl b/templates/custom/wait_count.tmpl new file mode 100644 index 000000000..77c49712d --- /dev/null +++ b/templates/custom/wait_count.tmpl @@ -0,0 +1,28 @@ +
+ {{$queue := ""}} + {{$gpuQueue := 0}} + {{range $k,$v :=.gpu_types}} + {{if eq $k 0}} + {{ $queue := $v.Queue }} + {{ end }} + {{ end }} + + {{ range $k,$v :=.QueuesDetail }} + {{if eq $k $queue}} + {{$gpuQueue :=$v}} + {{ end }} + {{ end }} + + {{.i18n.Tr "repo.wait_count_start"}} + {{if .QueuesDetail}} + {{ $gpuQueue }} + {{else}} + {{.WaitCount}} + {{ end }} + {{.i18n.Tr "repo.wait_count_end"}} +
diff --git a/templates/custom/wait_count_train.tmpl b/templates/custom/wait_count_train.tmpl new file mode 100644 index 000000000..ef6c4ed61 --- /dev/null +++ b/templates/custom/wait_count_train.tmpl @@ -0,0 +1,28 @@ +
+ {{$queue := ""}} + {{$gpuQueue := 0}} + {{range $k,$v :=.gpu_types}} + {{if eq $k 0}} + {{ $queue := $v.Queue }} + {{ end }} + {{ end }} + + {{ range $k,$v :=.QueuesDetail }} + {{if eq $k $queue}} + {{$gpuQueue :=$v}} + {{ end }} + {{ end }} + + {{.i18n.Tr "repo.wait_count_start"}} + {{if .QueuesDetail}} + {{ $gpuQueue }} + {{else}} + {{.WaitCount}} + {{ end }} + {{.i18n.Tr "repo.wait_count_end"}} +
diff --git a/templates/repo/cloudbrain/benchmark/new.tmpl b/templates/repo/cloudbrain/benchmark/new.tmpl index 76a4e5f0c..0509ce5bc 100755 --- a/templates/repo/cloudbrain/benchmark/new.tmpl +++ b/templates/repo/cloudbrain/benchmark/new.tmpl @@ -10,11 +10,9 @@ padding-left: 3rem !important; } - .min_title { + .min_title{ font-size: 14px !important; - padding-left: 6rem !important; margin-bottom: 2rem !important; - } .width81 { @@ -56,25 +54,26 @@ {{.CsrfTokenHtml}} -
- +
-
- +
+ - {{.i18n.Tr "cloudbrain.job_name_rule"}} + {{.i18n.Tr "cloudbrain.job_name_rule"}}
-
-
-
- +
+
-
+
- +   @@ -136,7 +135,8 @@ {{end}}
-
+
+ @@ -149,27 +149,28 @@ {{.CsrfTokenHtml}} -
- +
+ + {{template "custom/wait_count_train" .}}
-
- +
+ - {{.i18n.Tr "cloudbrain.job_name_rule"}} + {{.i18n.Tr "cloudbrain.job_name_rule"}}
-
- +
+
-
- +
+
-
+
 
-   + @@ -228,18 +229,16 @@
-
- +
+ {{.i18n.Tr "repo.cloudbrain.benchmark.evaluate_train"}}
-
- +
+ + @@ -273,7 +273,6 @@ $(document).ready(() => { $('.ui.search.dropdown.job_type').dropdown({ onChange: function (value, text, $selectedItem) { - console.log(value, text) if (value === "BRAINSCORE") { $('#brainscore_child_type').css('display', 'block') $('#benchmark_model_example').attr('href', 'https://git.openi.org.cn/BDIP/similarity2brain_ann') diff --git a/templates/repo/cloudbrain/inference/new.tmpl b/templates/repo/cloudbrain/inference/new.tmpl new file mode 100644 index 000000000..e42c7240a --- /dev/null +++ b/templates/repo/cloudbrain/inference/new.tmpl @@ -0,0 +1,480 @@ +{{template "base/head" .}} + +
+
+
+
+
+
+
+
+
+
+ {{template "repo/header" .}} +
+ {{template "base/alert" .}} + +

+ {{.i18n.Tr "repo.modelarts.train_job.new_infer"}} +

+
+ + + {{.CsrfTokenHtml}} + + + + {{if $.model_version}} + + {{else}} + + {{end}} + {{if $.label_names}} + + {{else}} + + {{end}} +

{{.i18n.Tr "repo.modelarts.train_job.basic_info"}}:

+
+
+ + + {{.i18n.Tr "cloudbrain.job_name_rule"}} +
+ +
+ + +
+
+ + +

{{.i18n.Tr "repo.modelarts.train_job.parameter_setting"}}:

+
+
+ + +
+
+ +
+
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ + {{template "custom/select_dataset_train" .}} + +
+ + {{if .bootFile}} + + {{else}} + + {{end}} + + + + {{.i18n.Tr "cloudbrain.view_sample"}} +
+ + +
+ + {{.i18n.Tr "repo.modelarts.train_job.add_run_parameter"}} + +
+ {{if ne 0 (len .params)}} + {{range $k ,$v := .params}} +
+
+ +
+
+ +
+ + + + +
+ {{end}} + {{end}} +
+
+ + + +
+ + +
+ + +
+ + + {{.i18n.Tr "repo.cloudbrain.cancel"}} +
+ + +
+
+
+{{template "base/footer" .}} + + diff --git a/templates/repo/cloudbrain/inference/show.tmpl b/templates/repo/cloudbrain/inference/show.tmpl new file mode 100644 index 000000000..7653376dd --- /dev/null +++ b/templates/repo/cloudbrain/inference/show.tmpl @@ -0,0 +1,605 @@ +{{template "base/head" .}} + +
+
+
+
+
+
+
+
+
+
+ {{template "repo/header" .}} +
+

+ +

+ {{with .task}} +
+ +
+
+
+ + + +
+ {{TimeSinceUnix1 .CreatedUnix}} + + {{$.i18n.Tr "repo.modelarts.status"}}: + {{.Status}} + + {{$.i18n.Tr "repo.modelarts.train_job.dura_time"}}: + {{$.duration}} + + +
+
+
+
+
+
+
+
+ +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ {{$.i18n.Tr "repo.cloudbrain_task"}} + +
+ {{.DisplayJobName}} +
+
+ {{$.i18n.Tr "repo.modelarts.status"}} + +
+ {{.Status}} +
+
+ {{$.i18n.Tr "repo.modelarts.train_job.start_time"}} + +
+ + {{if not (eq .StartTime 0)}} + {{TimeSinceUnix1 .StartTime}} + {{else}} + {{TimeSinceUnix1 .CreatedUnix}} + {{end}} + +
+
+ {{$.i18n.Tr "repo.modelarts.train_job.dura_time"}} + +
+ {{.TrainJobDuration}} +
+
+ {{$.i18n.Tr "repo.modelarts.train_job.resource_type"}} + +
+ {{$.resource_type}} +
+
+ {{$.i18n.Tr "repo.model.manage.description"}} + +
+ {{if .Description}} + {{.Description}} + {{else}} + -- + {{end}} +
+
+ 创建人 + +
+ {{.User.Name}} +
+
+ {{$.i18n.Tr "cloudbrain.mirror"}} + +
+ {{.Image}} +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ {{$.i18n.Tr "repo.modelarts.infer_job_model"}} + +
+ {{.ModelName}}   + {{$.i18n.Tr "repo.modelarts.version"}}:{{.ModelVersion}}   + +
+
+ {{$.i18n.Tr "repo.modelarts.infer_job_model_file"}} + +
+ {{.CkptName}} +
+
+ {{$.i18n.Tr "repo.modelarts.model_label"}} + +
+ + {{if .LabelName}} + {{range $.labelName}} + {{.}} + {{end}} + {{else}} + -- + {{end}} +
+
+ {{$.i18n.Tr "repo.modelarts.code_version"}} + +
+ {{.BranchName}} +
+
+ {{$.i18n.Tr "repo.modelarts.train_job.start_file"}} + +
+ {{.BootFile}} +
+
+ {{$.i18n.Tr "repo.modelarts.infer_dataset"}} + +
+ {{.DatasetName}} +
+
+ {{$.i18n.Tr "repo.modelarts.train_job.run_parameter"}} + +
+ {{if .Parameters}} + {{.Parameters}} + {{else}} + -- + {{end}} +
+
+ {{$.i18n.Tr "repo.modelarts.train_job.standard"}} + +
+ {{$.i18n.Tr "cloudbrain.gpu_num"}}:{{$.GpuNum}},{{$.i18n.Tr "cloudbrain.cpu_num"}}:{{$.CpuNum}},{{$.i18n.Tr "cloudbrain.memory"}}(MB):{{$.MemMiB}},{{$.i18n.Tr "cloudbrain.shared_memory"}}(MB):{{$.ShareMemMiB}} +
+
+
+
+
+ +
+
+ +
+
+ +
+ + + + + +
+ +
+ +
+ + + +
+ + + +
+ +
+
+ +
+
+
+ + {{end}} +
+ +
+{{template "base/footer" .}} + + \ No newline at end of file diff --git a/templates/repo/cloudbrain/new.tmpl b/templates/repo/cloudbrain/new.tmpl index 295fe0435..f0538261d 100755 --- a/templates/repo/cloudbrain/new.tmpl +++ b/templates/repo/cloudbrain/new.tmpl @@ -121,7 +121,7 @@ {{template "repo/header" .}}
- + {{template "base/alert" .}}

@@ -154,6 +154,7 @@ Ascend NPU
+ {{template "custom/wait_count" .}}
@@ -208,7 +209,7 @@
- {{end}}

{{.i18n.Tr "repo.modelarts.train_job.basic_info"}}:

-
- +
+ + + {{template "custom/wait_count_train" .}} +
+
+ - {{.i18n.Tr "cloudbrain.job_name_rule"}} + {{.i18n.Tr "cloudbrain.job_name_rule"}}
-
-    +
+   

{{.i18n.Tr "repo.modelarts.train_job.parameter_setting"}}:

-
+
-    + -
-
-       - {{range .engines}} - - {{end}} - -
-
- -
+
+ +
+ + +
+
-
-   +
+ {{else}} @@ -187,14 +215,14 @@
-
-    - {{.i18n.Tr "repo.modelarts.train_job.add_run_parameter"}} +
+ + {{.i18n.Tr "repo.modelarts.train_job.add_run_parameter"}}
{{if ne 0 (len .params)}} {{range $k ,$v := .params}} -
+
@@ -220,8 +248,8 @@
-
-         +
+
-
- +
+
- {{.i18n.Tr "cloudbrain.inference_output_path_rule"}} + {{.i18n.Tr "cloudbrain.inference_output_path_rule"}}
-
+
+ @@ -252,13 +281,14 @@ {{template "base/footer" .}} diff --git a/templates/repo/modelarts/notebook/new.tmpl b/templates/repo/modelarts/notebook/new.tmpl index 4e2b3951d..6ab16f941 100755 --- a/templates/repo/modelarts/notebook/new.tmpl +++ b/templates/repo/modelarts/notebook/new.tmpl @@ -46,6 +46,7 @@ Ascend NPU
+ {{template "custom/wait_count" .}}
diff --git a/templates/repo/modelarts/trainjob/new.tmpl b/templates/repo/modelarts/trainjob/new.tmpl index 5022bd41b..39f9f30f5 100755 --- a/templates/repo/modelarts/trainjob/new.tmpl +++ b/templates/repo/modelarts/trainjob/new.tmpl @@ -96,6 +96,7 @@
+
+ {{template "custom/wait_count_train" .}}
diff --git a/templates/repo/modelarts/trainjob/show.tmpl b/templates/repo/modelarts/trainjob/show.tmpl index 36039bfbc..aa0ab6836 100755 --- a/templates/repo/modelarts/trainjob/show.tmpl +++ b/templates/repo/modelarts/trainjob/show.tmpl @@ -327,8 +327,7 @@ {{$.i18n.Tr "repo.modelarts.log"}} 资源占用情况 - {{$.i18n.Tr "repo.model_download"}} + {{$.i18n.Tr "repo.model_download"}}
@@ -502,7 +501,7 @@
{{$.i18n.Tr "repo.modelarts.download_log"}} @@ -523,7 +522,7 @@ -
@@ -878,18 +877,6 @@ $('#name').val(modelName) $('#version').val("0.0.1") } - function renderSize(value) { - if (null == value || value == '') { - return "0 Bytes"; - } - var unitArr = new Array("Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"); - var index = 0; - var srcsize = parseFloat(value); - index = Math.floor(Math.log(srcsize) / Math.log(1024)); - var size = srcsize / Math.pow(1024, index); - size = size.toFixed(0);//保留的小数位数 - return size + unitArr[index]; - } function refreshStatus(version_name) { $.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}?version_name=${version_name}`, (data) => { // header status and duration @@ -901,7 +888,6 @@ $('#' + version_name + '-status').text(data.JobStatus) console.log(data) if (["KILLED", "FAILED", "START_FAILED", "STOPPED", "COMPLETED"].includes(data.JobStatus)) { - $(`#${version_name}-log-down`).removeClass('disabled').addClass('ti-download-file') $('#' + version_name + '-stop').addClass('disabled') } @@ -958,112 +944,12 @@ $('input[name=end_line]').val(data.EndLine) $('input[name=start_line]').val(data.StartLine) $(`#log_file${version_name}`).text(data.Content) - }).fail(function (err) { - console.log(err); - }); - } - function loadModelFile(version_name, parents, filename, init) { - parents = parents || '' - filename = filename || '' - init = init || '' - $.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/model_list?version_name=${version_name}&parentDir=${parents}`, (data) => { - $(`#dir_list${version_name}`).empty() - renderDir(data, version_name) - if (init === "init") { - $(`input[name=model${version_name}]`).val("") - $(`input[name=modelback${version_name}]`).val(version_name) - $(`#file_breadcrumb${version_name}`).empty() - let htmlBread = "" - htmlBread += `
${version_name}
` - htmlBread += "
/
" - $(`#file_breadcrumb${version_name}`).append(htmlBread) - } else { - renderBrend(version_name, parents, filename, init) + if(!data.CanLogDownload){ + $(`#${version_name}-log-down`).removeClass('ti-download-file').addClass('disabled') } }).fail(function (err) { - console.log(err, version_name); + console.log(err); }); - - } - function renderBrend(version_name, parents, filename, init) { - if (init == "folder") { - let htmlBrend = "" - let sectionName = $(`#file_breadcrumb${version_name} .active.section`).text() - let parents1 = $(`input[name=model${version_name}]`).val() - let filename1 = $(`input[name=modelback${version_name}]`).val() - if (parents1 === "") { - $(`#file_breadcrumb${version_name} .active.section`).replaceWith(`
${sectionName}`) - } else { - $(`#file_breadcrumb${version_name} .active.section`).replaceWith(`${sectionName}`) - } - - htmlBrend += `
${filename}
` - htmlBrend += "
/
" - $(`#file_breadcrumb${version_name}`).append(htmlBrend) - $(`input[name=model${version_name}]`).val(parents) - $(`input[name=modelback${version_name}]`).val(filename) - } else { - $(`input[name=model${version_name}]`).val(parents) - $(`input[name=modelback${version_name}]`).val(filename) - $(`#file_breadcrumb${version_name} a.section:contains(${filename})`).nextAll().remove() - $(`#file_breadcrumb${version_name} a.section:contains(${filename})`).replaceWith(`
${filename}
`) - $(`#file_breadcrumb${version_name} div.section:contains(${filename})`).append("
/
") - } - - } - function renderDir(data, version_name) { - let html = "" - html += "
" - html += "
" - html += "
" - html += "
" - html += "" - html += '' - // html += "" - for (let i = 0; i < data.Dirs.length; i++) { - let dirs_size = renderSize(data.Dirs[i].Size) - html += "" - html += "" - html += "" - - html += "" - html += "" - - } - html += "" - html += "
" - html += "" - html += "" - html += "" - if (data.Dirs[i].IsDir) { - html += `` - html += "" + data.Dirs[i].FileName + "" - } else { - if (downlaodFlag) { - html += `` - } - else { - html += `` - } - html += "" + data.Dirs[i].FileName + "" - } - html += '' - html += "" - html += "" - if (data.Dirs[i].IsDir) { - html += "" - } else { - html += "" + `${dirs_size}` + "" - } - - html += "" - html += "" + data.Dirs[i].ModTime + "" - html += "
" - html += "
" - html += "
" - html += "
" - html += "
" - $(`#dir_list${version_name}`).append(html) } function debounce(fn, delay) { let timer; diff --git a/templates/user/dashboard/cloudbrains.tmpl b/templates/user/dashboard/cloudbrains.tmpl index a3925b418..4c134fb30 100755 --- a/templates/user/dashboard/cloudbrains.tmpl +++ b/templates/user/dashboard/cloudbrains.tmpl @@ -87,7 +87,7 @@ {{else if eq .JobType "INFERENCE"}} {{.DisplayJobName}} @@ -113,7 +113,7 @@
{{$.i18n.Tr "repo.stop"}} @@ -203,7 +203,7 @@ {{end}}
{{$.CsrfTokenHtml}} 镜像 -       { + // 判断定时器是否存在,清除定时器 + if (timer) { + clearTimeout(timer); + } + + // 重新调用setTimeout + timer = setTimeout(() => { + fn.apply(this, args); + }, delay); + }; + } + + function logScroll(version_name) { + let container = document.querySelector(`#log${version_name}`); + console.log(container); + let scrollTop = container.scrollTop; + let scrollHeight = container.scrollHeight; + let clientHeight = container.clientHeight; + let scrollLeft = container.scrollLeft; + if ( + (parseInt(scrollTop) + clientHeight == scrollHeight || + parseInt(scrollTop) + clientHeight + 1 == scrollHeight || + parseInt(scrollTop) + clientHeight - 1 == scrollHeight) && + scrollLeft === 0 + ) { + let end_line = $(`#log${version_name} input[name=end_line]`).val(); + $.get( + `/api/v1/repos/${userName}/${repoPath}/modelarts/inference-job/${jobID}/log?version_name=${version_name}&base_line=${end_line}&lines=50&order=desc`, + (data) => { + if (data.Lines == 0) { + $(`.message${version_name} #header`).text("您已翻阅至日志底部"); + $(`.message${version_name}`).css("display", "block"); + setTimeout(function () { + $(`.message${version_name}`).css("display", "none"); + }, 1000); + } else { + if (end_line === data.EndLine) { + return; + } else { + $(`#log${version_name} input[name=end_line]`).val(data.EndLine); + $(`#log${version_name}`).append("
" + data.Content);
+            }
+          }
+        }
+      ).fail(function (err) {
+        console.log(err);
+      });
+    }
+    if (scrollTop == 0 && scrollLeft == 0) {
+      let start_line = $(`#log${version_name} input[name=start_line]`).val();
+      $.get(
+        `/api/v1/repos/${userName}/${repoPath}/modelarts/inference-job/${jobID}/log?version_name=${version_name}&base_line=${start_line}&lines=50&order=asc`,
+        (data) => {
+          if (data.Lines == 0) {
+            $(`.message${version_name} #header`).text("您已翻阅至日志顶部");
+            $(`.message${version_name}`).css("display", "block");
+            setTimeout(function () {
+              $(`.message${version_name}`).css("display", "none");
+            }, 1000);
+          } else {
+            $(`#log${version_name} input[name=start_line]`).val(data.StartLine); //如果变动就改变所对应的值
+            $(`#log${version_name}`).prepend("
" + data.Content);
+          }
+        }
+      ).fail(function (err) {
+        console.log(err);
+      });
+    }
+  }
+  const fn = debounce(logScroll, 500);
+  $(".log-scroll").scroll(function () {
+    let version_name = $(this).data("version");
+    fn(version_name);
+  });
+  function scrollAnimation(dom, currentY, targetY, currentX) {
+    let needScrollTop = targetY - currentY;
+    let _currentY = currentY;
+    setTimeout(() => {
+      // 一次调用滑动帧数,每次调用会不一样
+      //取总距离的十分之一
+      const dist = Math.ceil(needScrollTop / 10);
+      _currentY += dist;
+      //移动一个十分之一
+      dom.scrollTo(currentX || 0, _currentY, "smooth");
+      // 如果移动幅度小于十个像素,直接移动,否则递归调用,实现动画效果
+      if (needScrollTop > 10 || needScrollTop < -10) {
+        scrollAnimation(dom, _currentY, targetY);
+      } else {
+        dom.scrollTo(0, targetY, "smooth");
+      }
+    }, 1);
+  }
+
+  $(".log_top").click(function () {
+    // let logContentDom = document.querySelector('.log')
+    // if(!logContentDom)
+    //     return
+    // let version_name = $('.log_top').data('version')
+    let version_name = $(this).data("version");
+    let logContentDom = document.querySelector(`#log${version_name}`);
+
+    $(`#log_file${version_name}`).siblings("pre").remove();
+    $.get(
+      `/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?version_name=${version_name}&base_line=&lines=50&order=asc`,
+      (data) => {
+        $(`#log${version_name} input[name=end_line]`).val(data.EndLine); //如果变动就改变所对应的值
+        $(`#log${version_name} input[name=start_line]`).val(data.StartLine);
+        $(`#log${version_name}`).prepend("
" + data.Content);
+        $(`.message${version_name} #header`).text("您已翻阅至日志顶部");
+        $(`.message${version_name}`).css("display", "block");
+        setTimeout(function () {
+          $(`.message${version_name}`).css("display", "none");
+        }, 1000);
+        scrollAnimation(logContentDom, logContentDom.scrollTop, 0);
+      }
+    );
+  });
+  $(".log_bottom").click(function (e) {
+    let version_name = $(this).data("version");
+    let logContentDom = document.querySelector(`#log${version_name}`);
+    $(`#log_file${version_name}`).siblings("pre").remove();
+    $.get(
+      `/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?version_name=${version_name}&base_line=&lines=50&order=desc`,
+      (data) => {
+        $(`#log${version_name} input[name=end_line]`).val(data.EndLine); //如果变动就改变所对应的值
+        $(`#log${version_name} input[name=start_line]`).val(data.StartLine);
+        $(`#log${version_name}`).append("
" + data.Content);
+        $.get(
+          `/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?version_name=${version_name}&base_line=${data.EndLine}&lines=50&order=desc`,
+          (data) => {
+            if (data.Lines == 0) {
+              $(`.message${version_name} #header`).text("您已翻阅至日志底部");
+              $(`.message${version_name}`).css("display", "block");
+              setTimeout(function () {
+                $(`.message${version_name}`).css("display", "none");
+              }, 1000);
+            } else {
+              if (end_line === data.EndLine) {
+                return;
+              } else {
+                $(`#log${version_name} input[name=end_line]`).val(data.EndLine);
+                $(`#log${version_name}`).append("
" + data.Content);
+              }
+            }
+          }
+        ).fail(function (err) {
+          console.log(err);
+        });
+        scrollAnimation(
+          logContentDom,
+          logContentDom.scrollTop + 1,
+          logContentDom.scrollHeight - logContentDom.clientHeight
+        );
+      }
+    );
+  });
+
+  //
+  $(".content-pad").on("click", ".load-model-file", function () {
+    console.log("11111111111");
+    let version_name = $(this).data("version");
+    let parents = $(this).data("parents") || "";
+    let filename = $(this).data("filename") || "";
+    let init = $(this).data("init") || "";
+    let path = $(this).data("path");
+    let url = `/api/v1/repos${path}?version_name=${version_name}&parentDir=${parents}`;
+    console.log(url);
+    $.get(url, (data) => {
+      $(`#dir_list${version_name}`).empty();
+      renderDir(path, data, version_name);
+      if (init === "init") {
+        $(`input[name=model${version_name}]`).val("");
+        $(`input[name=modelback${version_name}]`).val(version_name);
+        $(`#file_breadcrumb${version_name}`).empty();
+        let htmlBread = "";
+        if (version_name) {
+          htmlBread += `
${version_name}
`; + } else { + htmlBread += `
result
`; + } + htmlBread += "
/
"; + $(`#file_breadcrumb${version_name}`).append(htmlBread); + } else { + renderBrend(path, version_name, parents, filename, init); + } + }).fail(function (err) { + console.log(err, version_name); + }); + }); + function renderSize(value) { + if (null == value || value == "") { + return "0 Bytes"; + } + var unitArr = new Array( + "Bytes", + "KB", + "MB", + "GB", + "TB", + "PB", + "EB", + "ZB", + "YB" + ); + var index = 0; + var srcsize = parseFloat(value); + index = Math.floor(Math.log(srcsize) / Math.log(1024)); + var size = srcsize / Math.pow(1024, index); + size = size.toFixed(0); //保留的小数位数 + return size + unitArr[index]; + } + function renderBrend(path, version_name, parents, filename, init) { + if (init == "folder") { + let htmlBrend = ""; + let sectionName = $( + `#file_breadcrumb${version_name} .active.section` + ).text(); + let parents1 = $(`input[name=model${version_name}]`).val(); + let filename1 = $(`input[name=modelback${version_name}]`).val(); + if (parents1 === "") { + $(`#file_breadcrumb${version_name} .active.section`).replaceWith( + `
${sectionName}` + ); + } else { + $(`#file_breadcrumb${version_name} .active.section`).replaceWith( + `${sectionName}` + ); + } + + htmlBrend += `
${filename}
`; + htmlBrend += "
/
"; + $(`#file_breadcrumb${version_name}`).append(htmlBrend); + $(`input[name=model${version_name}]`).val(parents); + $(`input[name=modelback${version_name}]`).val(filename); + } else { + $(`input[name=model${version_name}]`).val(parents); + $(`input[name=modelback${version_name}]`).val(filename); + $(`#file_breadcrumb${version_name} a.section:contains(${filename})`) + .nextAll() + .remove(); + $( + `#file_breadcrumb${version_name} a.section:contains(${filename})` + ).replaceWith(`
${filename}
`); + $( + `#file_breadcrumb${version_name} div.section:contains(${filename})` + ).append("
/
"); + } + } + + function renderDir(path, data, version_name) { + let html = ""; + html += "
"; + html += "
"; + html += "
"; + html += "
"; + html += ""; + html += ""; + // html += "" + for (let i = 0; i < data.Dirs.length; i++) { + let dirs_size = renderSize(data.Dirs[i].Size); + html += ""; + html += ""; + html += ""; + + html += ""; + html += ""; + } + html += ""; + html += "
"; + html += ""; + html += ""; + html += ""; + if (data.Dirs[i].IsDir) { + html += ``; + html += + "" + + data.Dirs[i].FileName + + ""; + } else { + if (downlaodFlag) { + html += ``; + } else { + html += ``; + } + html += + "" + + data.Dirs[i].FileName + + ""; + } + html += ""; + html += ""; + html += ""; + if (data.Dirs[i].IsDir) { + html += ""; + } else { + html += + "" + `${dirs_size}` + ""; + } + + html += ""; + html += + "" + data.Dirs[i].ModTime + ""; + html += "
"; + html += "
"; + html += "
"; + html += "
"; + html += "
"; + $(`#dir_list${version_name}`).append(html); + } +} diff --git a/web_src/js/features/cloudrbanin.js b/web_src/js/features/cloudrbanin.js index 95193a624..15cb47e97 100644 --- a/web_src/js/features/cloudrbanin.js +++ b/web_src/js/features/cloudrbanin.js @@ -1,335 +1,546 @@ export default async function initCloudrain() { - let debug_button = $('.cloudbrain_debug').data('debug') - let debug_again_button = $('.cloudbrain_debug').data('debug-again') - let timeid = window.setInterval(loadJobStatus, 15000); - let timeidShow = window.setInterval(loadShowJobStatus, 15000); - $(document).ready(loadJobStatus); - $(document).ready(loadShowJobStatus); - function loadJobStatus() { - $(".job-status").each((index, job) => { - const ID = job.dataset.jobid; - const repoPath = job.dataset.repopath; - // const computeResource = job.dataset.resource - const versionname = job.dataset.version - const status_text = $(`#${ID}-text`).text() - const finalState = ['STOPPED', 'CREATE_FAILED', 'UNAVAILABLE', 'DELETED', 'RESIZE_FAILED', 'SUCCEEDED', 'IMAGE_FAILED', 'SUBMIT_FAILED', 'DELETE_FAILED', 'KILLED', 'COMPLETED', 'FAILED', 'CANCELED', 'LOST', 'START_FAILED', 'SUBMIT_MODEL_FAILED', 'DEPLOY_SERVICE_FAILED', 'CHECK_FAILED'] - if (finalState.includes(status_text)) { - return - } - // const diffResource = computeResource == "NPU" ? 'modelarts/notebook' : 'cloudbrain' - $.get(`/api/v1/repos/${repoPath}/${ID}?version_name=${versionname}`, (data) => { - const ID = data.ID || data.JobID - const status = data.JobStatus - const duration = data.JobDuration - $('#duration-' + ID).text(duration) - if (status != status_text) { - $('#' + ID + '-icon').removeClass().addClass(status) - $('#' + ID + '-text').text(status) - finalState.includes(status) && $('#' + ID + '-stop').removeClass('blue').addClass('disabled') - } - if (status === "RUNNING") { - $('#ai-debug-' + ID).removeClass('disabled').addClass('blue').text(debug_button).css("margin", "0 1rem") - $('#model-image-' + ID).removeClass('disabled').addClass('blue') - } - if (status !== "RUNNING") { - // $('#model-debug-'+ID).removeClass('blue') - // $('#model-debug-'+ID).addClass('disabled') - $('#model-image-' + ID).removeClass('blue').addClass('disabled') - } - if (["CREATING", "STOPPING", "WAITING", "STARTING"].includes(status)) { - $('#ai-debug-' + ID).removeClass('blue').addClass('disabled') - } - if (['STOPPED', 'FAILED', 'START_FAILED', 'CREATE_FAILED', 'SUCCEEDED'].includes(status)) { - $('#ai-debug-' + ID).removeClass('disabled').addClass('blue').text(debug_again_button).css("margin", "0") - } - if (["RUNNING", "WAITING"].includes(status)) { - $('#ai-stop-' + ID).removeClass('disabled').addClass('blue') - } - if (["CREATING", "STOPPING", "STARTING", "STOPPED", "FAILED", "START_FAILED", "SUCCEEDED", "COMPLETED", "CREATE_FAILED"].includes(status)) { - $('#ai-stop-' + ID).removeClass('blue').addClass('disabled') - } - - if (["STOPPED", "FAILED", "START_FAILED", "KILLED", "COMPLETED", "SUCCEEDED"].includes(status)) { - $('#ai-delete-' + ID).removeClass('disabled').addClass('blue') - } else { - $('#ai-delete-' + ID).removeClass('blue').addClass('disabled') - } - if (["COMPLETED", "SUCCEEDED"].includes(status)) { - $('#ai-download-' + ID).removeClass('disabled').addClass('blue') - } else { - $('#ai-download-' + ID).removeClass('blue').addClass('disabled') - } - }).fail(function (err) { - console.log(err); - }); - }); - }; - - function loadShowJobStatus() { - $(".ui.accordion.border-according").each((index, job) => { - const jobID = job.dataset.jobid; - const repoPath = job.dataset.repopath; - const versionname = job.dataset.version - // ['IMAGE_FAILED','SUBMIT_FAILED','DELETE_FAILED','KILLED','COMPLETED','FAILED','CANCELED','LOST','START_FAILED'] - // if (job.textContent.trim() == 'IMAGE_FAILED' || job.textContent.trim() == 'SUBMIT_FAILED' || job.textContent.trim() == 'DELETE_FAILED' - // || job.textContent.trim() == 'KILLED' || job.textContent.trim() == 'COMPLETED' || job.textContent.trim() == 'FAILED' - // || job.textContent.trim() == 'CANCELED' || job.textContent.trim() == 'LOST') { - // return - // } - let status = $(`#${versionname}-status-span`).text() + let debug_button = $(".cloudbrain_debug").data("debug"); + let debug_again_button = $(".cloudbrain_debug").data("debug-again"); + let timeid = window.setInterval(loadJobStatus, 15000); + let timeidShow = window.setInterval(loadShowJobStatus, 15000); + $(document).ready(loadJobStatus); + $(document).ready(loadShowJobStatus); + function loadJobStatus() { + $(".job-status").each((index, job) => { + const ID = job.dataset.jobid; + const repoPath = job.dataset.repopath; + // const computeResource = job.dataset.resource + const versionname = job.dataset.version; + const status_text = $(`#${ID}-text`).text(); + const finalState = [ + "STOPPED", + "CREATE_FAILED", + "UNAVAILABLE", + "DELETED", + "RESIZE_FAILED", + "SUCCEEDED", + "IMAGE_FAILED", + "SUBMIT_FAILED", + "DELETE_FAILED", + "KILLED", + "COMPLETED", + "FAILED", + "CANCELED", + "LOST", + "START_FAILED", + "SUBMIT_MODEL_FAILED", + "DEPLOY_SERVICE_FAILED", + "CHECK_FAILED", + ]; + if (finalState.includes(status_text)) { + return; + } + // const diffResource = computeResource == "NPU" ? 'modelarts/notebook' : 'cloudbrain' + $.get( + `/api/v1/repos/${repoPath}/${ID}?version_name=${versionname}`, + (data) => { + const ID = data.ID || data.JobID; + const status = data.JobStatus; + const duration = data.JobDuration; + $("#duration-" + ID).text(duration); + if (status != status_text) { + $("#" + ID + "-icon") + .removeClass() + .addClass(status); + $("#" + ID + "-text").text(status); + finalState.includes(status) && + $("#" + ID + "-stop") + .removeClass("blue") + .addClass("disabled"); + } + if (status === "RUNNING") { + $("#ai-debug-" + ID) + .removeClass("disabled") + .addClass("blue") + .text(debug_button) + .css("margin", "0 1rem"); + $("#model-image-" + ID) + .removeClass("disabled") + .addClass("blue"); + } + if (status !== "RUNNING") { + // $('#model-debug-'+ID).removeClass('blue') + // $('#model-debug-'+ID).addClass('disabled') + $("#model-image-" + ID) + .removeClass("blue") + .addClass("disabled"); + } + if ( + ["CREATING", "STOPPING", "WAITING", "STARTING"].includes(status) + ) { + $("#ai-debug-" + ID) + .removeClass("blue") + .addClass("disabled"); + } + if ( + [ + "STOPPED", + "FAILED", + "START_FAILED", + "CREATE_FAILED", + "SUCCEEDED", + ].includes(status) + ) { + $("#ai-debug-" + ID) + .removeClass("disabled") + .addClass("blue") + .text(debug_again_button) + .css("margin", "0"); + } + if (["RUNNING", "WAITING"].includes(status)) { + $("#ai-stop-" + ID) + .removeClass("disabled") + .addClass("blue"); + } + if ( + [ + "CREATING", + "STOPPING", + "STARTING", + "STOPPED", + "FAILED", + "START_FAILED", + "SUCCEEDED", + "COMPLETED", + "CREATE_FAILED", + ].includes(status) + ) { + $("#ai-stop-" + ID) + .removeClass("blue") + .addClass("disabled"); + } - if (['IMAGE_FAILED', 'SUBMIT_FAILED', 'DELETE_FAILED', 'KILLED', 'COMPLETED', 'FAILED', 'CANCELED', 'LOST', 'START_FAILED', 'SUCCEEDED', 'STOPPED'].includes(status)) { - return - } - let stopArray = ["KILLED", "FAILED", "START_FAILED", "KILLING", "COMPLETED", "SUCCEEDED", "STOPPED"] - $.get(`/api/v1/repos/${repoPath}/${jobID}?version_name=${versionname}`, (data) => { - //$(`#${versionname}-duration-span`).text(data.JobDuration) - $(`#${versionname}-status-span span`).text(data.JobStatus) - $(`#${versionname}-status-span i`).attr("class", data.JobStatus) - // detail status and duration - //$('#'+versionname+'-duration').text(data.JobDuration) - $('#' + versionname + '-status').text(data.JobStatus) - if (stopArray.includes(data.JobStatus)) { - $('#' + versionname + '-stop').addClass('disabled') - } - if (data.JobStatus === "COMPLETED") { - $('#' + versionname + '-create-model').removeClass('disabled').addClass('blue') - } - }).fail(function (err) { - console.log(err); - }); - }); - }; + if ( + [ + "STOPPED", + "FAILED", + "START_FAILED", + "KILLED", + "COMPLETED", + "SUCCEEDED", + ].includes(status) + ) { + $("#ai-delete-" + ID) + .removeClass("disabled") + .addClass("blue"); + } else { + $("#ai-delete-" + ID) + .removeClass("blue") + .addClass("disabled"); + } + } + ).fail(function (err) { + console.log(err); + }); + }); + } + function loadShowJobStatus() { + $(".ui.accordion.border-according").each((index, job) => { + const jobID = job.dataset.jobid; + const repoPath = job.dataset.repopath; + const versionname = job.dataset.version; + // ['IMAGE_FAILED','SUBMIT_FAILED','DELETE_FAILED','KILLED','COMPLETED','FAILED','CANCELED','LOST','START_FAILED'] + // if (job.textContent.trim() == 'IMAGE_FAILED' || job.textContent.trim() == 'SUBMIT_FAILED' || job.textContent.trim() == 'DELETE_FAILED' + // || job.textContent.trim() == 'KILLED' || job.textContent.trim() == 'COMPLETED' || job.textContent.trim() == 'FAILED' + // || job.textContent.trim() == 'CANCELED' || job.textContent.trim() == 'LOST') { + // return + // } + let status = $(`#${versionname}-status-span`).text(); - function assertDelete(obj, versionName, repoPath) { - if (obj.style.color == "rgb(204, 204, 204)") { - return - } else { - const delId = obj.parentNode.id - let flag = 1; - $('.ui.basic.modal') - .modal({ - onDeny: function () { - flag = false - }, - onApprove: function () { - if (!versionName) { - document.getElementById(delId).submit() - } - else { - deleteVersion(versionName, repoPath) - } - flag = true - }, - onHidden: function () { - if (flag == false) { - $('.alert').html('您已取消操作').removeClass('alert-success').addClass('alert-danger').show().delay(1500).fadeOut(); - } - } - }) - .modal('show') - } - } - function deleteVersion(versionName, repoPath) { - const url = `/api/v1/repos/${repoPath}` - $.post(url, { version_name: versionName }, (data) => { - if (data.StatusOK === 0) { - location.reload() - } - }).fail(function (err) { - console.log(err); - }); - } - $('.ui.basic.ai_delete').click(function () { - const repoPath = this.dataset.repopath - const versionName = this.dataset.version - if (repoPath && versionName) { - assertDelete(this, versionName, repoPath) + if ( + [ + "IMAGE_FAILED", + "SUBMIT_FAILED", + "DELETE_FAILED", + "KILLED", + "COMPLETED", + "FAILED", + "CANCELED", + "LOST", + "START_FAILED", + "SUCCEEDED", + "STOPPED", + ].includes(status) + ) { + return; + } + let stopArray = [ + "KILLED", + "FAILED", + "START_FAILED", + "KILLING", + "COMPLETED", + "SUCCEEDED", + "STOPPED", + ]; + $.get( + `/api/v1/repos/${repoPath}/${jobID}?version_name=${versionname}`, + (data) => { + $(`#${versionname}-duration-span`).text(data.JobDuration); + $(`#${versionname}-status-span span`).text(data.JobStatus); + $(`#${versionname}-status-span i`).attr("class", data.JobStatus); + // detail status and duration + $("#" + versionname + "-duration").text(data.JobDuration); + $("#" + versionname + "-status").text(data.JobStatus); + if (stopArray.includes(data.JobStatus)) { + $("#" + versionname + "-stop").addClass("disabled"); + } + if (data.JobStatus === "COMPLETED") { + $("#" + versionname + "-create-model") + .removeClass("disabled") + .addClass("blue"); + } } - else { - assertDelete(this) - } - }) - function stopDebug(ID, stopUrl) { - $.ajax({ - type: "POST", - url: stopUrl, - data: $('#stopForm-' + ID).serialize(), - success: function (res) { - if (res.result_code === "0") { - $('#' + ID + '-icon').removeClass().addClass(res.status) - $('#' + ID + '-text').text(res.status) - if (res.status === "STOPPED") { - $('#ai-debug-' + ID).removeClass('disabled').addClass('blue').text(debug_again_button).css("margin", "0") - $('#ai-image-' + ID).removeClass('blue').addClass('disabled') - $('#ai-model-debug-' + ID).removeClass('blue').addClass('disabled') - $('#ai-delete-' + ID).removeClass('disabled').addClass('blue') - $('#ai-stop-' + ID).removeClass('blue').addClass('disabled') - } - else { - $('#ai-debug-' + ID).removeClass('blue').addClass('disabled') - $('#ai-stop-' + ID).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) + ).fail(function (err) { + console.log(err); + }); + }); + } + function assertDelete(obj, versionName, repoPath) { + if (obj.style.color == "rgb(204, 204, 204)") { + return; + } else { + const delId = obj.parentNode.id; + let flag = 1; + $(".ui.basic.modal") + .modal({ + onDeny: function () { + flag = false; + }, + onApprove: function () { + if (!versionName) { + document.getElementById(delId).submit(); + } else { + deleteVersion(versionName, repoPath); } + flag = true; + }, + onHidden: function () { + if (flag == false) { + $(".alert") + .html("您已取消操作") + .removeClass("alert-success") + .addClass("alert-danger") + .show() + .delay(1500) + .fadeOut(); + } + }, }) + .modal("show"); } - $('.ui.basic.ai_stop').click(function () { - const ID = this.dataset.jobid - const repoPath = this.dataset.repopath - stopDebug(ID, repoPath) - }) - - function stopVersion(version_name, ID, repoPath) { - const url = `/api/v1/repos/${repoPath}/${ID}/stop_version` - $.post(url, { version_name: version_name }, (data) => { - if (data.StatusOK === 0) { - $('#ai-stop-' + ID).removeClass('blue') - $('#ai-stop-' + ID).addClass('disabled') - refreshStatus(version_name, ID, repoPath) - } - }).fail(function (err) { - console.log(err); - }); + } + function deleteVersion(versionName, repoPath) { + const url = `/api/v1/repos/${repoPath}`; + $.post(url, { version_name: versionName }, (data) => { + if (data.StatusOK === 0 || data.Code === 0) { + location.reload(); + } + }).fail(function (err) { + console.log(err); + }); + } + $(".ui.basic.ai_delete").click(function () { + const repoPath = this.dataset.repopath; + const versionName = this.dataset.version; + if (repoPath && versionName) { + assertDelete(this, versionName, repoPath); + } else { + assertDelete(this); } - function refreshStatus(version_name, ID, repoPath) { + }); + function stopDebug(ID, stopUrl) { + $.ajax({ + type: "POST", + url: stopUrl, + data: $("#stopForm-" + ID).serialize(), + success: function (res) { + if (res.result_code === "0") { + $("#" + ID + "-icon") + .removeClass() + .addClass(res.status); + $("#" + ID + "-text").text(res.status); + if (res.status === "STOPPED") { + $("#ai-debug-" + ID) + .removeClass("disabled") + .addClass("blue") + .text(debug_again_button) + .css("margin", "0"); + $("#ai-image-" + ID) + .removeClass("blue") + .addClass("disabled"); + $("#ai-model-debug-" + ID) + .removeClass("blue") + .addClass("disabled"); + $("#ai-delete-" + ID) + .removeClass("disabled") + .addClass("blue"); + $("#ai-stop-" + ID) + .removeClass("blue") + .addClass("disabled"); + } else { + $("#ai-debug-" + ID) + .removeClass("blue") + .addClass("disabled"); + $("#ai-stop-" + ID) + .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); + }, + }); + } + $(".ui.basic.ai_stop").click(function () { + const ID = this.dataset.jobid; + const repoPath = this.dataset.repopath; + stopDebug(ID, repoPath); + }); - const url = `/api/v1/repos/${repoPath}/${ID}/?version_name${version_name}` - $.get(url, (data) => { - $(`#${ID}-icon`).attr("class", data.JobStatus) - // detail status and duration - $(`#${ID}-text`).text(data.JobStatus) - if (["STOPPED", "FAILED", "START_FAILED", "KILLED", "COMPLETED", "SUCCEEDED"].includes(data.JobStatus)) { - $('#ai-delete-' + ID).removeClass('disabled').addClass('blue') - } - }).fail(function (err) { - console.log(err); - }); - } - $('.ui.basic.ai_stop_version').click(function () { - const ID = this.dataset.jobid - const repoPath = this.dataset.repopath - const versionName = this.dataset.version - stopVersion(versionName, ID, repoPath) - }) - function getModelInfo(repoPath, modelName, versionName, jobName) { - $.get(`${repoPath}/modelmanage/show_model_info_api?name=${modelName}`, (data) => { - if (data.length === 0) { - $(`#${jobName}`).popup('toggle') + function stopVersion(version_name, ID, repoPath) { + const url = `/api/v1/repos/${repoPath}/${ID}/stop_version`; + $.post(url, { version_name: version_name }, (data) => { + if (data.StatusOK === 0) { + $("#ai-stop-" + ID).removeClass("blue"); + $("#ai-stop-" + ID).addClass("disabled"); + refreshStatus(version_name, ID, repoPath); + } + }).fail(function (err) { + console.log(err); + }); + } + + $("#refresh-status").click(function (e) { + let version_name = $(this).data("version"); + let ID = $(`#accordion${version_name}`).data("jobid"); + let repoPath = $(`#accordion${version_name}`).data("repopath"); + refreshStatusShow(version_name, ID, repoPath); + e.stopPropagation(); + }); + + function refreshStatusShow(version_name, ID, repoPath) { + $.get( + `/api/v1/repos/${repoPath}/${ID}?version_name=${version_name}`, + (data) => { + $(`#${version_name}-status-span span`).text(data.JobStatus); + $(`#${version_name}-status-span i`).attr("class", data.JobStatus); + $(`#${version_name}-duration-span`).text(data.JobDuration); + $("#" + versionname + "-duration").text(data.JobDuration); + $("#" + versionname + "-status").text(data.JobStatus); + } + ).fail(function (err) { + console.log(err); + }); + } + function refreshStatus(version_name, ID, repoPath) { + const url = `/api/v1/repos/${repoPath}/${ID}/?version_name${version_name}`; + $.get(url, (data) => { + $(`#${ID}-icon`).attr("class", data.JobStatus); + // detail status and duration + $(`#${ID}-text`).text(data.JobStatus); + if ( + [ + "STOPPED", + "FAILED", + "START_FAILED", + "KILLED", + "COMPLETED", + "SUCCEEDED", + ].includes(data.JobStatus) + ) { + $("#ai-delete-" + ID) + .removeClass("disabled") + .addClass("blue"); + } + }).fail(function (err) { + console.log(err); + }); + } + $(".ui.basic.ai_stop_version").click(function () { + const ID = this.dataset.jobid; + const repoPath = this.dataset.repopath; + const versionName = this.dataset.version; + stopVersion(versionName, ID, repoPath); + }); + function getModelInfo(repoPath, modelName, versionName, jobName) { + $.get( + `${repoPath}/modelmanage/show_model_info_api?name=${modelName}`, + (data) => { + if (data.length === 0) { + $(`#${jobName}`).popup("toggle"); + } else { + let versionData = data.filter((item) => { + return item.Version === versionName; + }); + if (versionData.length == 0) { + $(`#${jobName}`).popup("toggle"); + } else { + location.href = `${repoPath}/modelmanage/show_model_info?name=${modelName}`; + } + } + } + ); + } + $(".goto_modelmanage").click(function () { + const repoPath = this.dataset.repopath; + const modelName = this.dataset.modelname; + const versionName = this.dataset.version; + const jobName = this.dataset.jobname; + getModelInfo(repoPath, modelName, versionName, jobName); + }); + function debugAgain(ID, debugUrl, redirect_to) { + if ($("#" + ID + "-text").text() === "RUNNING") { + window.open(debugUrl + "debug"); + } else { + $.ajax({ + type: "POST", + url: debugUrl + "restart?redirect_to=" + redirect_to, + data: $("#debugAgainForm-" + ID).serialize(), + success: function (res) { + if (res["WechatRedirectUrl"]) { + window.location.href = res["WechatRedirectUrl"]; + } else if (res.result_code === "0") { + if (res.id !== ID) { + location.reload(); } else { - let versionData = data.filter((item) => { - return item.Version === versionName - }) - if (versionData.length == 0) { - $(`#${jobName}`).popup('toggle') - } - else { - location.href = `${repoPath}/modelmanage/show_model_info?name=${modelName}` - } + $("#" + ID + "-icon") + .removeClass() + .addClass(res.status); + $("#" + ID + "-text").text(res.status); + $("#ai-debug-" + ID) + .removeClass("blue") + .addClass("disabled"); + $("#ai-delete-" + ID) + .removeClass("blue") + .addClass("disabled"); + $("#ai-debug-" + ID) + .text(debug_button) + .css("margin", "0 1rem"); } - }) + } else { + $(".alert") + .html(res.error_msg) + .removeClass("alert-success") + .addClass("alert-danger") + .show() + .delay(2000) + .fadeOut(); + } + }, + error: function (res) { + console.log(res); + }, + }); } - $('.goto_modelmanage').click(function () { - const repoPath = this.dataset.repopath - const modelName = this.dataset.modelname - const versionName = this.dataset.version - const jobName = this.dataset.jobname - getModelInfo(repoPath, modelName, versionName, jobName) - }) - function debugAgain(ID, debugUrl, redirect_to) { - if ($('#' + ID + '-text').text() === "RUNNING") { - window.open(debugUrl + 'debug') - } else { - $.ajax({ - type: "POST", - url: debugUrl + 'restart?redirect_to=' + redirect_to, - data: $('#debugAgainForm-' + ID).serialize(), - success: function (res) { - if (res['WechatRedirectUrl']) { - window.location.href = res['WechatRedirectUrl'] - } - else if (res.result_code === "0") { - if (res.id !== ID) { - location.reload() - } else { - $('#' + ID + '-icon').removeClass().addClass(res.status) - $('#' + ID + '-text').text(res.status) - $('#ai-debug-' + ID).removeClass('blue').addClass('disabled') - $('#ai-delete-' + ID).removeClass('blue').addClass('disabled') - $('#ai-debug-' + ID).text(debug_button).css("margin", "0 1rem") - } - } else { - $('.alert').html(res.error_msg).removeClass('alert-success').addClass('alert-danger').show().delay(2000).fadeOut(); - } - }, - error: function (res) { - console.log(res) - } - }) - } + } + $(".ui.basic.ai_debug").click(function () { + const ID = this.dataset.jobid; + const repoPath = this.dataset.repopath; + const redirect_to = this.dataset.linkpath; + debugAgain(ID, repoPath, redirect_to); + }); + + function setWaitNums() { + console.log($(".cloudbrain-type")); + if ($(".cloudbrain-type").length === 0 && $(".gpu-type").length === 0) { + return; } - $('.ui.basic.ai_debug').click(function () { - const ID = this.dataset.jobid - const repoPath = this.dataset.repopath - const redirect_to = this.dataset.linkpath - debugAgain(ID, repoPath, redirect_to) - }) + let waitNums = $(".cloudbrain-type").data("queue").split("map")[1]; + let test = new Map(); + let waitNumsArray = waitNums.split(" "); + waitNumsArray.forEach((element, index) => { + if (index === 0) { + test.set(element.slice(1, -2), parseInt(element.slice(-1))); + } else if (index === waitNumsArray.length - 1) { + test.set(element.slice(0, -3), parseInt(element.slice(-2, -1))); + } else { + test.set(element.slice(0, -2), parseInt(element.slice(-1))); + } + }); + $(".ui.search.dropdown.gpu-type").dropdown({ + onChange: function (value, text, $selectedItem) { + let gpuTypeNums = test.get(value); + let gpuTypeNumString = + $(".cloudbrain-type").data("queue-start") + + " " + + gpuTypeNums + + " " + + $(".cloudbrain-type").data("queue-end"); + $("#gpu-nums").text(gpuTypeNumString); + }, + }); + } + setWaitNums(); } function userSearchControll() { - if ($('#userCloud').length === 0) { - return + if ($("#userCloud").length === 0) { + return; + } + const params = new URLSearchParams(window.location.search); + let jobType; + if ($(".cloudbrain_debug").length === 1) { + if (!params.get("jobType")) { + jobType = $(".cloudbrain_debug").data("allTask"); + } else { + if (params.get("jobType") === "DEBUG") { + jobType = $(".cloudbrain_debug").data("debug-task"); + } else if (params.get("jobType") === "TRAIN") { + jobType = $(".cloudbrain_debug").data("train-task"); + } else if (params.get("jobType") === "INFERENCE") { + jobType = $(".cloudbrain_debug").data("inference-task"); + } else { + jobType = $(".cloudbrain_debug").data("benchmark-task"); + } } - const params = new URLSearchParams(window.location.search) - let jobType - if ($('.cloudbrain_debug').length === 1) { - if (!params.get('jobType')) { - jobType = $('.cloudbrain_debug').data('allTask') - } else { - if (params.get('jobType') === 'DEBUG') { - jobType = $('.cloudbrain_debug').data('debug-task') - } else if (params.get('jobType') === 'TRAIN') { - jobType = $('.cloudbrain_debug').data('train-task') - } - else if (params.get('jobType') === 'INFERENCE') { - jobType = $('.cloudbrain_debug').data('inference-task') - } - else { - jobType = $('.cloudbrain_debug').data('benchmark-task') - } - } - } - let listType = !params.get('listType') ? $('.cloudbrain_debug').data('all-compute') : params.get('listType') - let jobStatus = !params.get('jobStatus') ? $('.cloudbrain_debug').data('all-status') : params.get('jobStatus').toUpperCase() - const dropdownValueArray = [jobType, listType, jobStatus] - $('#userCloud .default.text ').each(function (index, e) { - $(e).text(dropdownValueArray[index]) - }) + } + let listType = !params.get("listType") + ? $(".cloudbrain_debug").data("all-compute") + : params.get("listType"); + let jobStatus = !params.get("jobStatus") + ? $(".cloudbrain_debug").data("all-status") + : params.get("jobStatus").toUpperCase(); + const dropdownValueArray = [jobType, listType, jobStatus]; + $("#userCloud .default.text ").each(function (index, e) { + $(e).text(dropdownValueArray[index]); + }); } function AdaminSearchControll() { - if ($('#adminCloud').length === 0) { - return - } - const params = new URLSearchParams(window.location.search) - let jobType = !params.get('jobType') ? $('.cloudbrain_debug').data('all-task') : params.get('jobType') - let listType = !params.get('listType') ? $('.cloudbrain_debug').data('all-compute') : params.get('listType') - let jobStatus = !params.get('jobStatus') ? $('.cloudbrain_debug').data('all-status') : params.get('jobStatus').toUpperCase() - const dropdownValueArray = [jobType, listType, jobStatus] - $('#adminCloud .default.text ').each(function (index, e) { - $(e).text(dropdownValueArray[index]) - }) + if ($("#adminCloud").length === 0) { + return; + } + const params = new URLSearchParams(window.location.search); + let jobType = !params.get("jobType") + ? $(".cloudbrain_debug").data("all-task") + : params.get("jobType"); + let listType = !params.get("listType") + ? $(".cloudbrain_debug").data("all-compute") + : params.get("listType"); + let jobStatus = !params.get("jobStatus") + ? $(".cloudbrain_debug").data("all-status") + : params.get("jobStatus").toUpperCase(); + const dropdownValueArray = [jobType, listType, jobStatus]; + $("#adminCloud .default.text ").each(function (index, e) { + $(e).text(dropdownValueArray[index]); + }); } -userSearchControll() -AdaminSearchControll() - - - +userSearchControll(); +AdaminSearchControll(); diff --git a/web_src/js/index.js b/web_src/js/index.js index 754d6ca76..53dba8a88 100755 --- a/web_src/js/index.js +++ b/web_src/js/index.js @@ -43,6 +43,7 @@ import Contributors from "./components/Contributors.vue"; import Model from "./components/Model.vue"; import WxAutorize from "./components/WxAutorize.vue"; import initCloudrain from "./features/cloudrbanin.js"; +import initCloudrainSow from "./features/cloudbrainShow.js"; import initImage from "./features/images.js"; import selectDataset from "./components/dataset/selectDataset.vue"; // import $ from 'jquery.js' @@ -2917,6 +2918,7 @@ $(document).ready(async () => { initTribute(); initDropDown(); initCloudrain(); + initCloudrainSow(); initImage(); initContextMenu(); @@ -3711,9 +3713,9 @@ function initVueDataset() { if (!el) { return; } - let link = $('#square-link').data('link') - let repolink = $('.dataset-repolink').data('repolink') - let datasetType = $('.dataset-repolink').data('dataset-type') + let link = $("#square-link").data("link"); + let repolink = $(".dataset-repolink").data("repolink"); + let datasetType = $(".dataset-repolink").data("dataset-type"); const clearBtn = document.getElementsByClassName("clear_dataset_value"); const params = new URLSearchParams(location.search); for (let i = 0; i < clearBtn.length; i++) { @@ -3873,10 +3875,10 @@ function initVueDataset() { mounted() { this.getTypeList(); - if (!!document.getElementById('dataset-repolink-init')) { + if (!!document.getElementById("dataset-repolink-init")) { // this.datasetType = location.href.indexOf('cloudbrain') !== -1 ? 0 : 1 - this.datasetType = $('#dataset-repolink-init').data("dataset-type") - this.getCurrentRepoDataset(this.repolink, this.datasetType) + this.datasetType = $("#dataset-repolink-init").data("dataset-type"); + this.getCurrentRepoDataset(this.repolink, this.datasetType); } const params = new URLSearchParams(location.search); @@ -3897,13 +3899,13 @@ function initVueDataset() { this.ruleForm1 = ruleForm; // this.getEditInit() - this.starItems = starItems - this.starActives = starActives - this.taskLists = taskLists - this.licenseLists = licenseLists - this.descfile = dataset_file_desc - this.repolink = repolink - this.datasetType = datasetType + this.starItems = starItems; + this.starActives = starActives; + this.taskLists = taskLists; + this.licenseLists = licenseLists; + this.descfile = dataset_file_desc; + this.repolink = repolink; + this.datasetType = datasetType; }, methods: { copyUrl(url) { @@ -3924,18 +3926,18 @@ function initVueDataset() { handleCurrentChange(val) { this.page = val; switch (this.activeName) { - case 'first': - this.getCurrentRepoDataset(this.repolink, this.datasetType) - break - case 'second': - this.getMyDataset(this.repolink, this.datasetType) - break - case 'third': - this.getPublicDataset(this.repolink, this.datasetType) - break - case 'fourth': - this.getStarDataset(this.repolink, this.datasetType) - break + case "first": + this.getCurrentRepoDataset(this.repolink, this.datasetType); + break; + case "second": + this.getMyDataset(this.repolink, this.datasetType); + break; + case "third": + this.getPublicDataset(this.repolink, this.datasetType); + break; + case "fourth": + this.getStarDataset(this.repolink, this.datasetType); + break; } }, handleCheckedChange(val) { @@ -4276,18 +4278,18 @@ function initVueDataset() { }, refreshStatusDataset() { switch (this.activeName) { - case 'first': - this.getCurrentRepoDataset(this.repolink, this.datasetType) - break - case 'second': - this.getMyDataset(this.repolink, this.datasetType) - break - case 'third': - this.getPublicDataset(this.repolink, this.datasetType) - break - case 'fourth': - this.getStarDataset(this.repolink, this.datasetType) - break + case "first": + this.getCurrentRepoDataset(this.repolink, this.datasetType); + break; + case "second": + this.getMyDataset(this.repolink, this.datasetType); + break; + case "third": + this.getPublicDataset(this.repolink, this.datasetType); + break; + case "fourth": + this.getStarDataset(this.repolink, this.datasetType); + break; } }, getCurrentRepoDataset(repoLink, type) { @@ -4398,44 +4400,44 @@ function initVueDataset() { }, searchDataset() { switch (this.activeName) { - case 'first': - this.page = 1 - this.getCurrentRepoDataset(this.repolink, this.datasetType) - break - case 'second': - this.page = 1 - this.getMyDataset(this.repolink, this.datasetType) - break - case 'third': - this.page = 1 - this.getPublicDataset(this.repolink, this.datasetType) - break - case 'fourth': - this.page = 1 - this.getStarDataset(this.repolink, this.datasetType) - break + case "first": + this.page = 1; + this.getCurrentRepoDataset(this.repolink, this.datasetType); + break; + case "second": + this.page = 1; + this.getMyDataset(this.repolink, this.datasetType); + break; + case "third": + this.page = 1; + this.getPublicDataset(this.repolink, this.datasetType); + break; + case "fourth": + this.page = 1; + this.getStarDataset(this.repolink, this.datasetType); + break; } }, }, watch: { searchDataItem() { switch (this.activeName) { - case 'first': - this.page = 1 - this.getCurrentRepoDataset(this.repolink, this.datasetType) - break - case 'second': - this.page = 1 - this.getMyDataset(this.repolink, this.datasetType) - break - case 'third': - this.page = 1 - this.getPublicDataset(this.repolink, this.datasetType) - break - case 'fourth': - this.page = 1 - this.getStarDataset(this.repolink, this.datasetType) - break + case "first": + this.page = 1; + this.getCurrentRepoDataset(this.repolink, this.datasetType); + break; + case "second": + this.page = 1; + this.getMyDataset(this.repolink, this.datasetType); + break; + case "third": + this.page = 1; + this.getPublicDataset(this.repolink, this.datasetType); + break; + case "fourth": + this.page = 1; + this.getStarDataset(this.repolink, this.datasetType); + break; } }, }, diff --git a/web_src/less/openi.less b/web_src/less/openi.less index 9325f6a74..0c30d1c92 100644 --- a/web_src/less/openi.less +++ b/web_src/less/openi.less @@ -1210,12 +1210,27 @@ i.SUCCEEDED { max-width: 6.38px; visibility: hidden; } +.label-fix-width { + width: 140px !important; + text-align: right; + font-family: SourceHanSansSC-medium !important; + color: rgba(16, 16, 16, 100) !important; + font-size: 14px !important; +} .inline.min_title.fields.required .label-fix-width:after { margin: -0.2em 0 0 0.2em; content: "*"; max-width: 6.38px; visibility: hidden; } + +.tooltip-wati-count { + display: flex; + align-items: center; + margin-left: 260px; + color: #f2711c; + margin-top: 0.5rem; +} #dir_list { max-height: 500px; overflow: auto;