diff --git a/models/cloudbrain_static.go b/models/cloudbrain_static.go index cb99f9ff5..a7678b267 100644 --- a/models/cloudbrain_static.go +++ b/models/cloudbrain_static.go @@ -1,7 +1,6 @@ package models import ( - "fmt" "strconv" "time" @@ -313,10 +312,6 @@ func InsertCloudbrainDurationStatistic(cloudbrainDurationStatistic *CloudbrainDu return xStatistic.Insert(cloudbrainDurationStatistic) } -func GetDurationStatisticByDate(date string, hour int, aiCenterCode string, accCardType string) (*CloudbrainDurationStatistic, error) { - cb := &CloudbrainDurationStatistic{DayTime: date, HourTime: hour, AiCenterCode: aiCenterCode, AccCardType: accCardType} - return getDurationStatistic(cb) -} func getDurationStatistic(cb *CloudbrainDurationStatistic) (*CloudbrainDurationStatistic, error) { has, err := x.Get(cb) if err != nil { @@ -327,26 +322,6 @@ func getDurationStatistic(cb *CloudbrainDurationStatistic) (*CloudbrainDurationS return cb, nil } -func DeleteCloudbrainDurationStatisticHour(date string, hour int, aiCenterCode string, accCardType string) error { - sess := xStatistic.NewSession() - defer sess.Close() - if err := sess.Begin(); err != nil { - return fmt.Errorf("Begin: %v", err) - } - - if _, err := sess.Where("day_time = ? AND hour_time = ? AND ai_center_code = ? AND acc_card_type = ?", date, hour, aiCenterCode, accCardType).Delete(&CloudbrainDurationStatistic{}); err != nil { - return fmt.Errorf("Delete: %v", err) - } - - if err := sess.Commit(); err != nil { - sess.Close() - return fmt.Errorf("Commit: %v", err) - } - - sess.Close() - return nil -} - func GetCanUseCardInfo() ([]*ResourceQueue, error) { sess := x.NewSession() defer sess.Close() @@ -402,11 +377,11 @@ func GetDurationRecordUpdateTime() ([]*CloudbrainDurationStatistic, error) { return CloudbrainDurationStatistics, nil } -func DeleteCloudbrainDurationStatistic() error { +func DeleteCloudbrainDurationStatistic(beginTime timeutil.TimeStamp, endTime timeutil.TimeStamp) error { sess := xStatistic.NewSession() defer sess.Close() - if _, err := sess.Exec("TRUNCATE TABLE cloudbrain_duration_statistic"); err != nil { - log.Info("TRUNCATE cloudbrain_duration_statistic error.") + if _, err := sess.Exec("DELETE FROM cloudbrain_duration_statistic WHERE cloudbrain_duration_statistic.date_time BETWEEN ? AND ?", beginTime, endTime); err != nil { + log.Info("DELETE cloudbrain_duration_statistic data error.") return err } return nil diff --git a/models/repo.go b/models/repo.go index f0760108b..832e3fc37 100755 --- a/models/repo.go +++ b/models/repo.go @@ -1279,7 +1279,7 @@ func CreateRepository(ctx DBContext, doer, u *User, repo *Repository, opts ...Cr } if setting.Service.AutoWatchNewRepos { - if err = watchRepo(ctx.e, doer.ID, repo.ID, true); err != nil { + if err = watchRepo(ctx.e, doer.ID, repo.ID, true, ReceiveAllNotification); err != nil { return fmt.Errorf("watchRepo: %v", err) } } diff --git a/models/repo_watch.go b/models/repo_watch.go index 573a2d78a..7c43ee352 100644 --- a/models/repo_watch.go +++ b/models/repo_watch.go @@ -24,6 +24,14 @@ const ( RepoWatchModeAuto // 3 ) +// NotifyType specifies what kind of watch the user has on a repository +type NotifyType int8 + +const ( + RejectAllNotification NotifyType = 0 + ReceiveAllNotification NotifyType = 9 +) + var ActionChan = make(chan *Action, 200) var ActionChan4Task = make(chan Action, 200) @@ -34,6 +42,7 @@ type Watch struct { RepoID int64 `xorm:"UNIQUE(watch)"` Mode RepoWatchMode `xorm:"SMALLINT NOT NULL DEFAULT 1"` CreatedUnix int64 `xorm:"created"` + NotifyType NotifyType `xorm:"SMALLINT NOT NULL DEFAULT 0"` } // getWatch gets what kind of subscription a user has on a given repository; returns dummy record if none found @@ -60,8 +69,20 @@ func IsWatching(userID, repoID int64) bool { return err == nil && isWatchMode(watch.Mode) } +// GetWatchNotifyType +func GetWatchNotifyType(userID, repoID int64) NotifyType { + watch, err := getWatch(x, userID, repoID) + if err != nil { + return RejectAllNotification + } + return watch.NotifyType +} + func watchRepoMode(e Engine, watch Watch, mode RepoWatchMode) (err error) { if watch.Mode == mode { + if _, err := e.ID(watch.ID).Cols("notify_type").Update(watch); err != nil { + return err + } return nil } if mode == RepoWatchModeAuto && (watch.Mode == RepoWatchModeDont || isWatchMode(watch.Mode)) { @@ -109,7 +130,7 @@ func WatchRepoMode(userID, repoID int64, mode RepoWatchMode) (err error) { return watchRepoMode(x, watch, mode) } -func watchRepo(e Engine, userID, repoID int64, doWatch bool) (err error) { +func watchRepo(e Engine, userID, repoID int64, doWatch bool, notifyTypes ...NotifyType) (err error) { var watch Watch if watch, err = getWatch(e, userID, repoID); err != nil { return err @@ -119,14 +140,19 @@ func watchRepo(e Engine, userID, repoID int64, doWatch bool) (err error) { } else if !doWatch { err = watchRepoMode(e, watch, RepoWatchModeNone) } else { + notifyType := RejectAllNotification + if len(notifyTypes) > 0 { + notifyType = notifyTypes[0] + } + watch.NotifyType = notifyType err = watchRepoMode(e, watch, RepoWatchModeNormal) } return err } // WatchRepo watch or unwatch repository. -func WatchRepo(userID, repoID int64, watch bool) (err error) { - return watchRepo(x, userID, repoID, watch) +func WatchRepo(userID, repoID int64, watch bool, notifyType ...NotifyType) (err error) { + return watchRepo(x, userID, repoID, watch, notifyType...) } func getWatchers(e Engine, repoID int64) ([]*Watch, error) { @@ -156,6 +182,7 @@ func getRepoWatchersIDs(e Engine, repoID int64) ([]int64, error) { return ids, e.Table("watch"). Where("watch.repo_id=?", repoID). And("watch.mode<>?", RepoWatchModeDont). + And("watch.notify_type > ?", RejectAllNotification). Select("user_id"). Find(&ids) } diff --git a/models/resource_specification.go b/models/resource_specification.go index 7a11edd05..2f815818b 100644 --- a/models/resource_specification.go +++ b/models/resource_specification.go @@ -298,6 +298,15 @@ func ResourceSpecOffShelf(id int64) (int64, error) { return n, err } +func GetResourceSpecificationByIds(ids []int64) ([]*Specification, error) { + r := make([]*Specification, 0) + err := x.In("resource_specification.id", ids). + Join("INNER", "resource_queue", "resource_queue.id = resource_specification.queue_id"). + Find(&r) + return r, err + +} + func GetResourceSpecification(r *ResourceSpecification) (*ResourceSpecification, error) { has, err := x.Get(r) if err != nil { diff --git a/models/user.go b/models/user.go index b21858e37..c421455bc 100755 --- a/models/user.go +++ b/models/user.go @@ -346,7 +346,7 @@ func (u *User) DashboardLink() string { if u.IsOrganization() { return setting.AppSubURL + "/org/" + u.Name + "/dashboard/" } - return setting.AppSubURL + "/" + return setting.AppSubURL + "/dashboard" } // HomeLink returns the user or organization home page link. diff --git a/models/user_mail.go b/models/user_mail.go index 8bf74b81b..8388da068 100755 --- a/models/user_mail.go +++ b/models/user_mail.go @@ -216,6 +216,27 @@ func (email *EmailAddress) updateActivation(e Engine, activate bool) error { return updateUserCols(e, user, "rands") } +// UpdateEmailAddress update an email address of given user. +func (email *EmailAddress) UpdateEmailAddress(newEmailAddress string) error { + return email.updateEmailAddress(x, newEmailAddress) +} +func (email *EmailAddress) updateEmailAddress(e Engine, newEmailAddress string) error { + user, err := getUserByID(e, email.UID) + if err != nil { + return err + } + if user.Rands, err = GetUserSalt(); err != nil { + return err + } + user.Email = newEmailAddress + user.AvatarEmail = newEmailAddress + email.Email = newEmailAddress + if _, err := e.ID(email.ID).Cols("email").Update(email); err != nil { + return err + } + return updateUserCols(e, user, "email", "avatar_email") +} + // DeleteEmailAddress deletes an email address of given user. func DeleteEmailAddress(email *EmailAddress) (err error) { var deleted int64 diff --git a/modules/auth/user_form.go b/modules/auth/user_form.go index ad78607ab..521585264 100755 --- a/modules/auth/user_form.go +++ b/modules/auth/user_form.go @@ -88,6 +88,10 @@ type RegisterForm struct { Agree bool } +type UpdateEmailForm struct { + NewEmail string `binding:"Required;MaxSize(254)"` +} + // Validate valideates the fields func (f *RegisterForm) 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 8d4e57670..f8a6525d2 100755 --- a/modules/cloudbrain/cloudbrain.go +++ b/modules/cloudbrain/cloudbrain.go @@ -145,7 +145,7 @@ func isAdminOrImageCreater(ctx *context.Context, image *models.Image, err error) func AdminOrOwnerOrJobCreaterRight(ctx *context.Context) { var id = ctx.Params(":id") - job, err := models.GetCloudbrainByID(id) + job, err := GetCloudBrainByIdOrJobId(id) if err != nil { log.Error("GetCloudbrainByID failed:%v", err.Error()) ctx.NotFound(ctx.Req.URL.RequestURI(), nil) @@ -161,7 +161,7 @@ func AdminOrOwnerOrJobCreaterRight(ctx *context.Context) { func AdminOrJobCreaterRight(ctx *context.Context) { var id = ctx.Params(":id") - job, err := models.GetCloudbrainByID(id) + job, err := GetCloudBrainByIdOrJobId(id) if err != nil { log.Error("GetCloudbrainByID failed:%v", err.Error()) ctx.NotFound(ctx.Req.URL.RequestURI(), nil) @@ -177,7 +177,7 @@ func AdminOrJobCreaterRight(ctx *context.Context) { func AdminOrOwnerOrJobCreaterRightForTrain(ctx *context.Context) { var jobID = ctx.Params(":jobid") - job, err := models.GetCloudbrainByJobID(jobID) + job, err := GetCloudBrainByIdOrJobId(jobID) if err != nil { log.Error("GetCloudbrainByJobID failed:%v", err.Error()) ctx.NotFound(ctx.Req.URL.RequestURI(), nil) @@ -193,7 +193,7 @@ func AdminOrOwnerOrJobCreaterRightForTrain(ctx *context.Context) { func AdminOrJobCreaterRightForTrain(ctx *context.Context) { var jobID = ctx.Params(":jobid") - job, err := models.GetCloudbrainByJobID(jobID) + job, err := GetCloudBrainByIdOrJobId(jobID) if err != nil { log.Error("GetCloudbrainByJobID failed:%v", err.Error()) ctx.NotFound(ctx.Req.URL.RequestURI(), nil) @@ -652,3 +652,16 @@ func IsElementExist(s []string, str string) bool { } return false } + +func GetCloudBrainByIdOrJobId(id string) (*models.Cloudbrain,error) { + _, err := strconv.ParseInt(id, 10, 64) + var job *models.Cloudbrain + if err != nil { + + job, err = models.GetCloudbrainByJobID(id) + } else { + job, err = models.GetCloudbrainByID(id) + + } + return job,err +} diff --git a/modules/context/repo.go b/modules/context/repo.go index 7c425c8c0..3bdc34f0d 100755 --- a/modules/context/repo.go +++ b/modules/context/repo.go @@ -474,6 +474,7 @@ func RepoAssignment() macaron.Handler { if ctx.IsSigned { ctx.Data["IsWatchingRepo"] = models.IsWatching(ctx.User.ID, repo.ID) + ctx.Data["WatchNotifyType"] = models.GetWatchNotifyType(ctx.User.ID, repo.ID) ctx.Data["IsStaringRepo"] = models.IsStaring(ctx.User.ID, repo.ID) ctx.Data["IsStaringDataset"] = models.IsDatasetStaringByRepoId(ctx.User.ID, repo.ID) diff --git a/modules/modelarts/modelarts.go b/modules/modelarts/modelarts.go index dd502dfd0..b59be307b 100755 --- a/modules/modelarts/modelarts.go +++ b/modules/modelarts/modelarts.go @@ -1,13 +1,18 @@ package modelarts import ( + "encoding/base64" "encoding/json" "errors" "fmt" + "io/ioutil" + "net/http" "path" "strconv" "strings" + "code.gitea.io/gitea/modules/cloudbrain" + "code.gitea.io/gitea/modules/modelarts_cd" "code.gitea.io/gitea/models" @@ -23,7 +28,7 @@ const ( //notebook storageTypeOBS = "obs" autoStopDuration = 4 * 60 * 60 - autoStopDurationMs = 4 * 60 * 60 * 1000 + AutoStopDurationMs = 4 * 60 * 60 * 1000 MORDELART_USER_IMAGE_ENGINE_ID = -1 DataSetMountPath = "/home/ma-user/work" NotebookEnv = "Python3" @@ -276,7 +281,7 @@ func GenerateTask(ctx *context.Context, jobName, uuid, description, flavor strin return nil } -func GenerateNotebook2(ctx *context.Context, displayJobName, jobName, uuid, description, imageId string, spec *models.Specification) error { +func GenerateNotebook2(ctx *context.Context, displayJobName, jobName, uuid, description, imageId string, spec *models.Specification, bootFile string,autoStopDurationInMs int64) (string, error) { if poolInfos == nil { json.Unmarshal([]byte(setting.PoolInfos), &poolInfos) } @@ -284,14 +289,14 @@ func GenerateNotebook2(ctx *context.Context, displayJobName, jobName, uuid, desc imageName, err := GetNotebookImageName(imageId) if err != nil { log.Error("GetNotebookImageName failed: %v", err.Error()) - return err + return "", err } createTime := timeutil.TimeStampNow() jobResult, err := createNotebook2(models.CreateNotebook2Params{ JobName: jobName, Description: description, Flavor: spec.SourceSpecId, - Duration: autoStopDurationMs, + Duration: autoStopDurationInMs, ImageID: imageId, PoolID: poolInfos.PoolInfo[0].PoolId, Feature: models.NotebookFeature, @@ -316,10 +321,10 @@ func GenerateNotebook2(ctx *context.Context, displayJobName, jobName, uuid, desc }) if errTemp != nil { log.Error("InsertCloudbrainTemp failed: %v", errTemp.Error()) - return errTemp + return "", errTemp } } - return err + return "", err } task := &models.Cloudbrain{ Status: jobResult.Status, @@ -334,6 +339,7 @@ func GenerateNotebook2(ctx *context.Context, displayJobName, jobName, uuid, desc Uuid: uuid, ComputeResource: models.NPUResource, Image: imageName, + BootFile: bootFile, Description: description, CreatedUnix: createTime, UpdatedUnix: createTime, @@ -342,12 +348,12 @@ func GenerateNotebook2(ctx *context.Context, displayJobName, jobName, uuid, desc err = models.CreateCloudbrain(task) if err != nil { - return err + return "", err } stringId := strconv.FormatInt(task.ID, 10) notification.NotifyOtherTask(ctx.User, ctx.Repo.Repository, stringId, displayJobName, models.ActionCreateDebugNPUTask) - return nil + return jobResult.ID, nil } func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (jobId string, err error) { @@ -907,6 +913,11 @@ func HandleNotebookInfo(task *models.Cloudbrain) error { if task.FlavorCode == "" { task.FlavorCode = result.Flavor } + + if oldStatus != task.Status && task.Status == string(models.ModelArtsRunning) && task.BootFile != "" { + uploadNoteBookFile(task, result) + + } err = models.UpdateJob(task) if err != nil { log.Error("UpdateJob(%s) failed:%v", task.DisplayJobName, err) @@ -917,6 +928,81 @@ func HandleNotebookInfo(task *models.Cloudbrain) error { return nil } +func uploadNoteBookFile(task *models.Cloudbrain, result *models.GetNotebook2Result) { + jupyterUrl := result.Url + "?token=" + result.Token + + cookies, xsrf := getCookiesAndCsrf(jupyterUrl) + if xsrf == "" { + log.Error("browser jupyterUrl failed:%v", task.DisplayJobName) + } else { + + codePath := setting.JobPath + task.JobName + cloudbrain.CodeMountPath + fileContents, err := ioutil.ReadFile(codePath + "/" + task.BootFile) + if err != nil { + log.Error("read jupyter file failed:%v", task.DisplayJobName, err) + } + + base64Content := base64.StdEncoding.EncodeToString(fileContents) + client := getRestyClient() + uploadUrl := getJupyterBaseUrl(result.Url) + "api/contents/" + path.Base(task.BootFile) + res, err := client.R(). + SetCookies(cookies). + SetHeader("X-XSRFToken", xsrf). + SetBody(map[string]interface{}{ + "type": "file", + "format": "base64", + "name": path.Base(task.BootFile), + "path": path.Base(task.BootFile), + "content": base64Content}). + Put(uploadUrl) + if err != nil { + log.Error("upload jupyter file failed:%v", task.DisplayJobName, err) + } else if res.StatusCode() != http.StatusCreated { + log.Error("upload jupyter file failed:%v", task.DisplayJobName, err) + } + + } + +} + +func getJupyterBaseUrl(url string) string { + jupyterUrlLength := len(url) + baseUrl := url[0 : jupyterUrlLength-len(path.Base(url))] + return baseUrl +} + +func getCookiesAndCsrf(jupyterUrl string) ([]*http.Cookie, string) { + log.Info("jupyter url:"+jupyterUrl) + var cookies []*http.Cookie + const retryTimes = 10 + for i := 0; i < retryTimes; i++ { + res, err := http.Get(jupyterUrl) + if err != nil { + log.Error("browser jupyterUrl failed.",err) + if i==retryTimes-1{ + return cookies, "" + } + + } else { + cookies = res.Cookies() + xsrf := "" + for _, cookie := range cookies { + if cookie.Name == "_xsrf" { + xsrf = cookie.Value + break + } + + } + if xsrf != "" { + return cookies, xsrf + } + + } + } + return cookies, "" + +} + func SyncTempStatusJob() { jobs, err := models.GetCloudBrainTempJobs() if err != nil { diff --git a/modules/modelarts/resty.go b/modules/modelarts/resty.go index c38300606..3ccba9011 100755 --- a/modules/modelarts/resty.go +++ b/modules/modelarts/resty.go @@ -280,7 +280,7 @@ sendjob: SetHeader("Content-Type", "application/json"). SetAuthToken(TOKEN). SetResult(&result). - Post(HOST + "/v1/" + setting.ProjectID + urlNotebook2 + "/" + jobID + "/" + param.Action + "?duration=" + strconv.Itoa(autoStopDurationMs)) + Post(HOST + "/v1/" + setting.ProjectID + urlNotebook2 + "/" + jobID + "/" + param.Action + "?duration=" + strconv.Itoa(AutoStopDurationMs)) if err != nil { return &result, fmt.Errorf("resty ManageNotebook2: %v", err) diff --git a/modules/modelarts_cd/modelarts.go b/modules/modelarts_cd/modelarts.go index 330b048ca..93032fa89 100755 --- a/modules/modelarts_cd/modelarts.go +++ b/modules/modelarts_cd/modelarts.go @@ -88,18 +88,18 @@ type Parameters struct { } `json:"parameter"` } -func GenerateNotebook(ctx *context.Context, displayJobName, jobName, uuid, description, imageId string, spec *models.Specification) error { +func GenerateNotebook(ctx *context.Context, displayJobName, jobName, uuid, description, imageId string, spec *models.Specification, bootFile string,autoStopDurationInMs int64) (string, error) { imageName, err := GetNotebookImageName(imageId) if err != nil { log.Error("GetNotebookImageName failed: %v", err.Error()) - return err + return "", err } createTime := timeutil.TimeStampNow() jobResult, err := createNotebook(models.CreateNotebookWithoutPoolParams{ JobName: jobName, Description: description, Flavor: spec.SourceSpecId, - Duration: autoStopDurationMs, + Duration: autoStopDurationInMs, ImageID: imageId, Feature: models.NotebookFeature, Volume: models.VolumeReq{ @@ -123,10 +123,10 @@ func GenerateNotebook(ctx *context.Context, displayJobName, jobName, uuid, descr }) if errTemp != nil { log.Error("InsertCloudbrainTemp failed: %v", errTemp.Error()) - return errTemp + return "", errTemp } } - return err + return "", err } task := &models.Cloudbrain{ Status: jobResult.Status, @@ -145,16 +145,17 @@ func GenerateNotebook(ctx *context.Context, displayJobName, jobName, uuid, descr CreatedUnix: createTime, UpdatedUnix: createTime, Spec: spec, + BootFile: bootFile, } err = models.CreateCloudbrain(task) if err != nil { - return err + return "", err } stringId := strconv.FormatInt(task.ID, 10) notification.NotifyOtherTask(ctx.User, ctx.Repo.Repository, stringId, displayJobName, models.ActionCreateDebugNPUTask) - return nil + return jobResult.ID, nil } func GetNotebookImageName(imageId string) (string, error) { @@ -175,41 +176,3 @@ func GetNotebookImageName(imageId string) (string, error) { return imageName, nil } - -/* -func HandleNotebookInfo(task *models.Cloudbrain) error { - - result, err := GetNotebook(task.JobID) - if err != nil { - log.Error("GetNotebook2(%s) failed:%v", task.DisplayJobName, err) - return err - } - - if result != nil { - oldStatus := task.Status - task.Status = result.Status - if task.StartTime == 0 && result.Lease.UpdateTime > 0 { - task.StartTime = timeutil.TimeStamp(result.Lease.UpdateTime / 1000) - } - if task.EndTime == 0 && models.IsModelArtsDebugJobTerminal(task.Status) { - task.EndTime = timeutil.TimeStampNow() - } - task.CorrectCreateUnix() - task.ComputeAndSetDuration() - if oldStatus != task.Status { - notification.NotifyChangeCloudbrainStatus(task, oldStatus) - } - if task.FlavorCode == "" { - task.FlavorCode = result.Flavor - } - err = models.UpdateJob(task) - if err != nil { - log.Error("UpdateJob(%s) failed:%v", task.DisplayJobName, err) - return err - } - } - - return nil -} - -*/ diff --git a/modules/setting/setting.go b/modules/setting/setting.go index e237d5a8a..374e6a99d 100755 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -715,6 +715,21 @@ var ( TeamName string }{} + FileNoteBook = struct { + ProjectName string + ImageGPU string + SpecIdGPU int64 + SpecIdCPU int64 + ImageIdNPU string + SpecIdNPU int64 + ImageIdNPUCD string + SpecIdNPUCD int64 + ImageCPUDescription string + ImageGPUDescription string + ImageNPUDescription string + ImageNPUCDDescription string + }{} + ModelConvert = struct { GPU_PYTORCH_IMAGE string GpuQueue string @@ -1580,6 +1595,20 @@ func NewContext() { Course.OrgName = sec.Key("org_name").MustString("") Course.TeamName = sec.Key("team_name").MustString("") + sec = Cfg.Section("file_notebook") + FileNoteBook.ProjectName = sec.Key("project_name").MustString("openi-notebook") + FileNoteBook.ImageIdNPU = sec.Key("imageid_npu").MustString("") + FileNoteBook.ImageGPU = sec.Key("image_gpu").MustString("") + FileNoteBook.SpecIdCPU = sec.Key("specid_cpu").MustInt64(-1) + FileNoteBook.SpecIdGPU = sec.Key("specid_gpu").MustInt64(-1) + FileNoteBook.SpecIdNPU = sec.Key("specid_npu").MustInt64(-1) + FileNoteBook.ImageIdNPUCD = sec.Key("imageid_npu_cd").MustString("") + FileNoteBook.SpecIdNPUCD = sec.Key("specid_npu_cd").MustInt64(-1) + FileNoteBook.ImageCPUDescription = sec.Key("image_cpu_desc").MustString("") + FileNoteBook.ImageGPUDescription = sec.Key("image_gpu_desc").MustString("") + FileNoteBook.ImageNPUDescription = sec.Key("image_npu_desc").MustString("") + FileNoteBook.ImageNPUCDDescription = sec.Key("image_npu_cd_desc").MustString("") + getGrampusConfig() getModelartsCDConfig() getModelConvertConfig() diff --git a/modules/structs/cloudbrain.go b/modules/structs/cloudbrain.go index 866c85dad..9ea5601c9 100644 --- a/modules/structs/cloudbrain.go +++ b/modules/structs/cloudbrain.go @@ -41,6 +41,14 @@ type CreateTrainJobOption struct { SpecId int64 `json:"spec_id" binding:"Required"` } +type CreateFileNotebookJobOption struct { + Type int `json:"type"` //0 CPU 1 GPU 2 NPU + File string `json:"file" binding:"Required"` + BranchName string `json:"branch_name" binding:"Required"` + OwnerName string `json:"owner_name" binding:"Required"` + ProjectName string `json:"project_name" binding:"Required"` +} + type Cloudbrain struct { ID int64 `json:"id"` JobID string `json:"job_id"` diff --git a/modules/templates/helper.go b/modules/templates/helper.go index 3e424454b..c314127f1 100755 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -151,6 +151,9 @@ func NewFuncMap() []template.FuncMap { "EscapePound": func(str string) string { return strings.NewReplacer("%", "%25", "#", "%23", " ", "%20", "?", "%3F").Replace(str) }, + "IpynbBool":func(str string) bool{ + return strings.Contains(str, ".ipynb") + }, "nl2br": func(text string) template.HTML { return template.HTML(strings.Replace(template.HTMLEscapeString(text), "\n", "
", -1)) }, diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index f3381d2ed..3f52cedbe 100755 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -397,9 +397,12 @@ authorize_application_created_by = This application was created by %s. authorize_application_description = If you grant the access, it will be able to access and write to all your account information, including private repos and organisations. authorize_title = Authorize "%s" to access your account? authorization_failed = Authorization failed -authorization_failed_desc = The authorization failed because we detected an invalid request. Please contact the maintainer of the app you've tried to authorize. +authorization_failed_desc = The authorization failed because we detected an invalid request. Please contact the maintainer of the app you have tried to authorize. disable_forgot_password_mail = Account recovery is disabled. Please contact your site administrator. sspi_auth_failed = SSPI authentication failed +change_email = Change email +change_email_address = Change email address +new_email_address = New email address [phone] format_err=The format of phone number is wrong. query_err=Fail to query phone number, please try again later. @@ -1015,6 +1018,8 @@ readme = README readme_helper = Select a README file template. auto_init = Initialize Repository (Adds .gitignore, License and README) create_repo = Create Repository +failed_to_create_repo=Failed to create repository, please try again later. +failed_to_create_notebook_repo=Failed to create %s repository, please check whether you have the same name project, if yes please update or delete it first. create_course = Publish Course failed_to_create_course=Failed to publish course, please try again later. default_branch = Default Branch @@ -1049,6 +1054,10 @@ model_experience = Model Experience model_noright=You have no right to do the operation. model_rename=Duplicate model name, please modify model name. +notebook_file_not_exist=Notebook file does not exist. +notebook_select_wrong=Please select a Notebook(.ipynb) file first. +notebook_file_no_right=You have no right to access the Notebook(.ipynb) file. + date=Date repo_add=Project Increment repo_total=Project Total @@ -1228,7 +1237,7 @@ cloudbrain.benchmark.evaluate_test=Test Script cloudbrain.benchmark.types={"type":[{"id":1,"rank_link":"https://git.openi.org.cn/benchmark/?username=admin&algType=detection","first":"Target detection","second":[{"id":1,"value":"None","attachment":"84cf39c4-d8bc-41aa-aaa3-182ce289b105","owner":"yangzhx","repo_name":"detection_benchmark_script"}]},{"id":2,"rank_link":"https://git.openi.org.cn/benchmark/?username=admin&algType=reid","first":"Target re-identification","second":[{"id":1,"value":"Vehicle re-identification","attachment":"84cf39c4-d8bc-41aa-aaa3-182ce289b105","owner":"JiahongXu","repo_name":"benchmark_reID_script"},{"id":2,"value":"Image-based person re-identification","attachment":"84cf39c4-d8bc-41aa-aaa3-182ce289b105","owner":"JiahongXu","repo_name":"benchmark_reID_script"}]},{"id":3,"rank_link":"https://git.openi.org.cn/benchmark/?username=admin&algType=tracking","first":"Multi-target tracking","second":[{"id":1,"value":"None","attachment":"84cf39c4-d8bc-41aa-aaa3-182ce289b105","owner":"lix07","repo_name":"MOT_benchmark_script"}]}]} cloudbrain.morethanonejob=You already have a running or waiting task, create it after that task is over. cloudbrain.morethanonejob1=You have created an equivalent task that is waiting or running, please wait for the task to finish before creating it. -cloudbrain.morethanonejob2=You can view all your Cloud Brain tasks in Home > Cloudbrain Task . +cloudbrain.morethanonejob2=You can view all your Cloud Brain tasks in Home > Cloudbrain Task . modelarts.infer_job_model = Model modelarts.infer_job_model_file = Model File @@ -1402,6 +1411,11 @@ star = Star fork = Fork download_archive = Download Repository star_fail=Failed to %s the dataset. +watched=Watched +notWatched=Not watched +un_watch=Unwatch +watch_all=Watch all +watch_no_notify=Watch but not notify no_desc = No Description no_label = No labels @@ -1443,6 +1457,7 @@ blame = Blame normal_view = Normal View line = line lines = lines +notebook_open = Open in Notebook editor.new_file = New File editor.upload_file = Upload File diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index f4017be27..3e26ae251 100755 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -403,6 +403,9 @@ authorization_failed=授权失败 authorization_failed_desc=授权失败,这是一个无效的请求。请联系尝试授权应用的管理员。 disable_forgot_password_mail = Account recovery is disabled. Please contact your site administrator. sspi_auth_failed=SSPI 认证失败 +change_email=修改邮箱 +change_email_address=修改邮箱地址 +new_email_address=新邮箱地址 [phone] format_err=手机号格式错误。 query_err=查询手机号失败,请稍后再试。 @@ -1020,6 +1023,8 @@ readme=自述 readme_helper=选择自述文件模板。 auto_init=初始化存储库 (添加. gitignore、许可证和自述文件) create_repo=创建项目 +failed_to_create_repo=创建项目失败,请稍后再试。 +failed_to_create_notebook_repo=创建项目%s失败,请检查您是否有同名的项目,如果有请先手工修改或删除后重试。 create_course=发布课程 failed_to_create_course=发布课程失败,请稍后再试。 default_branch=默认分支 @@ -1048,6 +1053,9 @@ model_experience = 模型体验 model_noright=您没有操作权限。 model_rename=模型名称重复,请修改模型名称 +notebook_file_not_exist=Notebook文件不存在。 +notebook_select_wrong=请先选择Notebook(.ipynb)文件。 +notebook_file_no_right=您没有这个Notebook文件的读权限。 date=日期 repo_add=新增项目 @@ -1418,6 +1426,11 @@ star=点赞 fork=派生 download_archive=下载此项目 star_fail=%s失败。 +watched=已关注 +notWatched=未关注 +un_watch=不关注 +watch_all=关注所有动态 +watch_no_notify=关注但不提醒动态 no_desc=暂无描述 @@ -1461,6 +1474,8 @@ normal_view=普通视图 line=行 lines=行 +notebook_open = 在Notebook中打开 + editor.new_file=新建文件 editor.upload_file=上传文件 editor.edit_file=编辑文件 diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 2afbb9b7d..14badfdb4 100755 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -737,6 +737,12 @@ func RegisterRoutes(m *macaron.Macaron) { m.Get("/my_favorite", repo.MyFavoriteDatasetMultiple) }, reqToken(), repoAssignment()) + m.Group("/file_notebook", func() { + m.Get("", reqToken(), repo.GetFileNoteBookInfo) + m.Post("/create", reqToken(), reqWeChat(), bind(api.CreateFileNotebookJobOption{}), repo.CreateFileNoteBook) + + }) + m.Group("/repos", func() { m.Get("/search", repo.Search) diff --git a/routers/api/v1/repo/cloudbrain.go b/routers/api/v1/repo/cloudbrain.go index f2a784f16..f1b2751f8 100755 --- a/routers/api/v1/repo/cloudbrain.go +++ b/routers/api/v1/repo/cloudbrain.go @@ -79,6 +79,75 @@ func CloudBrainShow(ctx *context.APIContext) { ctx.JSON(http.StatusOK, models.BaseMessageWithDataApi{Code: 0, Message: "", Data: convert.ToCloudBrain(task)}) } +func CreateFileNoteBook(ctx *context.APIContext, option api.CreateFileNotebookJobOption) { + cloudbrainTask.FileNotebookCreate(ctx.Context, option) +} + +func GetFileNoteBookInfo(ctx *context.APIContext) { + //image description spec description waiting count + + specs, err := models.GetResourceSpecificationByIds([]int64{setting.FileNoteBook.SpecIdCPU, setting.FileNoteBook.SpecIdGPU, setting.FileNoteBook.SpecIdNPU, setting.FileNoteBook.SpecIdNPUCD}) + if err != nil { + log.Error("Fail to query specifications", err) + ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.notebook_query_fail"))) + return + } + + var specCPU, specGpu, specNPU, specNPUCD *api.SpecificationShow + var specGpuQueueCode string + for _, spec := range specs { + if spec.ID == setting.FileNoteBook.SpecIdCPU { + specCPU = convert.ToSpecification(spec) + } else if spec.ID == setting.FileNoteBook.SpecIdGPU { + specGpu = convert.ToSpecification(spec) + specGpuQueueCode = spec.QueueCode + } else if spec.ID == setting.FileNoteBook.SpecIdNPU { + specNPU = convert.ToSpecification(spec) + } else if spec.ID == setting.FileNoteBook.SpecIdNPUCD { + specNPUCD = convert.ToSpecification(spec) + } + } + + waitCountNpu := cloudbrain.GetWaitingCloudbrainCount(models.TypeCloudBrainTwo, "") + + queuesMap, err := cloudbrain.GetQueuesDetail() + if err != nil { + log.Error("Fail to query gpu queues waiting count", err) + ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.notebook_query_fail"))) + return + } + waitCountGPU := (*queuesMap)[specGpuQueueCode] + if !setting.ModelartsCD.Enabled{ + ctx.JSON(http.StatusOK, map[string]interface{}{ + "code": 0, + "projectName":setting.FileNoteBook.ProjectName, + "specCpu": specCPU, + "specGpu": specGpu, + "specNpu": specNPU, + "waitCountGpu": waitCountGPU, + "waitCountNpu": waitCountNpu, + "imageCpuDescription": setting.FileNoteBook.ImageCPUDescription, + "imageGpuDescription": setting.FileNoteBook.ImageGPUDescription, + "imageNpuDescription": setting.FileNoteBook.ImageNPUDescription, + + }) + } else{ + ctx.JSON(http.StatusOK, map[string]interface{}{ + "code": 0, + "projectName":setting.FileNoteBook.ProjectName, + "specCpu": specCPU, + "specGpu": specGpu, + "specNpu": specNPUCD, + "waitCountGpu": waitCountGPU, + "waitCountNpu": waitCountNpu, + "imageCpuDescription": setting.FileNoteBook.ImageCPUDescription, + "imageGpuDescription": setting.FileNoteBook.ImageGPUDescription, + "imageNpuDescription": setting.FileNoteBook.ImageNPUCDDescription, + }) + + } + +} func CreateCloudBrain(ctx *context.APIContext, option api.CreateTrainJobOption) { if option.Type == cloudbrainTask.TaskTypeCloudbrainOne { @@ -141,10 +210,11 @@ func GetCloudbrainTask(ctx *context.APIContext) { ) ID := ctx.Params(":id") - job, err := models.GetCloudbrainByID(ID) + + job,err := cloudbrain.GetCloudBrainByIdOrJobId(ID) + if err != nil { ctx.NotFound(err) - log.Error("GetCloudbrainByID failed:", err) return } if job.JobType == string(models.JobTypeModelSafety) { diff --git a/routers/api/v1/repo/cloudbrain_dashboard.go b/routers/api/v1/repo/cloudbrain_dashboard.go index 446522fc2..09e65b007 100755 --- a/routers/api/v1/repo/cloudbrain_dashboard.go +++ b/routers/api/v1/repo/cloudbrain_dashboard.go @@ -123,8 +123,9 @@ func GetOverviewDuration(ctx *context.Context) { recordBeginTime := recordCloudbrain[0].Cloudbrain.CreatedUnix now := time.Now() endTime := now - // worker_server_num := 1 - // cardNum := 1 + var workServerNumber int64 + var cardNum int64 + durationAllSum := int64(0) cardDuSum := int64(0) @@ -138,52 +139,60 @@ func GetOverviewDuration(ctx *context.Context) { c2NetDuration := int64(0) cDCenterDuration := int64(0) - cloudbrains, _, err := models.CloudbrainAllStatic(&models.CloudbrainsOptions{ - Type: models.TypeCloudBrainAll, - BeginTimeUnix: int64(recordBeginTime), - EndTimeUnix: endTime.Unix(), - }) - if err != nil { - ctx.ServerError("Get cloudbrains failed:", err) - return - } - models.LoadSpecs4CloudbrainInfo(cloudbrains) - - for _, cloudbrain := range cloudbrains { - cloudbrain = cloudbrainService.UpdateCloudbrainAiCenter(cloudbrain) - CardDurationString := repo.GetCloudbrainCardDuration(cloudbrain.Cloudbrain) - CardDuration := models.ConvertStrToDuration(CardDurationString) - // if cloudbrain.Cloudbrain.WorkServerNumber >= 1 { - // worker_server_num = cloudbrain.Cloudbrain.WorkServerNumber - // } else { - // worker_server_num = 1 - // } - // if cloudbrain.Cloudbrain.Spec == nil { - // cardNum = 1 - // } else { - // cardNum = cloudbrain.Cloudbrain.Spec.AccCardsNum - // } - // duration := cloudbrain.Duration - // duration := cloudbrain.Duration - duration := models.ConvertStrToDuration(cloudbrain.TrainJobDuration) - // CardDuration := cloudbrain.Duration * int64(worker_server_num) * int64(cardNum) - - if cloudbrain.Cloudbrain.Type == models.TypeCloudBrainOne { - cloudBrainOneDuration += duration - cloudBrainOneCardDuSum += CardDuration - } else if cloudbrain.Cloudbrain.Type == models.TypeCloudBrainTwo { - cloudBrainTwoDuration += duration - cloudBrainTwoCardDuSum += CardDuration - } else if cloudbrain.Cloudbrain.Type == models.TypeC2Net { - c2NetDuration += duration - c2NetCardDuSum += CardDuration - } else if cloudbrain.Cloudbrain.Type == models.TypeCDCenter { - cDCenterDuration += duration - cDNetCardDuSum += CardDuration + page := 1 + pagesize := 10000 + count := pagesize + // Each time a maximum of 10000 pieces of data are detected to the memory, batch processing + for count == pagesize && count != 0 { + cloudbrains, _, err := models.CloudbrainAllStatic(&models.CloudbrainsOptions{ + ListOptions: models.ListOptions{ + Page: page, + PageSize: pagesize, + }, + Type: models.TypeCloudBrainAll, + BeginTimeUnix: int64(recordBeginTime), + EndTimeUnix: endTime.Unix(), + }) + if err != nil { + ctx.ServerError("Get cloudbrains failed:", err) + return } + models.LoadSpecs4CloudbrainInfo(cloudbrains) + + for _, cloudbrain := range cloudbrains { + cloudbrain = cloudbrainService.UpdateCloudbrainAiCenter(cloudbrain) + if cloudbrain.Cloudbrain.Spec != nil { + cardNum = int64(cloudbrain.Cloudbrain.Spec.AccCardsNum) + } else { + cardNum = 1 + } + if cloudbrain.Cloudbrain.WorkServerNumber >= 1 { + workServerNumber = int64(cloudbrain.Cloudbrain.WorkServerNumber) + } else { + workServerNumber = 1 + } + duration := models.ConvertStrToDuration(cloudbrain.TrainJobDuration) + CardDuration := workServerNumber * int64(cardNum) * duration + + if cloudbrain.Cloudbrain.Type == models.TypeCloudBrainOne { + cloudBrainOneDuration += duration + cloudBrainOneCardDuSum += CardDuration + } else if cloudbrain.Cloudbrain.Type == models.TypeCloudBrainTwo { + cloudBrainTwoDuration += duration + cloudBrainTwoCardDuSum += CardDuration + } else if cloudbrain.Cloudbrain.Type == models.TypeC2Net { + c2NetDuration += duration + c2NetCardDuSum += CardDuration + } else if cloudbrain.Cloudbrain.Type == models.TypeCDCenter { + cDCenterDuration += duration + cDNetCardDuSum += CardDuration + } - durationAllSum += duration - cardDuSum += CardDuration + durationAllSum += duration + cardDuSum += CardDuration + } + count = len(cloudbrains) + page += 1 } ctx.JSON(http.StatusOK, map[string]interface{}{ "cloudBrainOneCardDuSum": cloudBrainOneCardDuSum, diff --git a/routers/api/v1/repo/modelarts.go b/routers/api/v1/repo/modelarts.go index e0db9eda3..127ddd835 100755 --- a/routers/api/v1/repo/modelarts.go +++ b/routers/api/v1/repo/modelarts.go @@ -6,6 +6,7 @@ package repo import ( + "code.gitea.io/gitea/modules/cloudbrain" "encoding/json" "net/http" "path" @@ -37,11 +38,14 @@ func GetModelArtsNotebook2(ctx *context.APIContext) { ) ID := ctx.Params(":id") - job, err := models.GetCloudbrainByID(ID) + + job,err := cloudbrain.GetCloudBrainByIdOrJobId(ID) + if err != nil { ctx.NotFound(err) return } + err = modelarts.HandleNotebookInfo(job) if err != nil { ctx.NotFound(err) diff --git a/routers/repo/aisafety.go b/routers/repo/aisafety.go index b638a486b..6176fcda5 100644 --- a/routers/repo/aisafety.go +++ b/routers/repo/aisafety.go @@ -11,7 +11,8 @@ import ( "os" "strconv" "strings" - "time" + + cloudbrainService "code.gitea.io/gitea/services/cloudbrain" "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/aisafety" @@ -483,7 +484,6 @@ func isTaskNotFinished(status string) bool { } func AiSafetyCreateForGetGPU(ctx *context.Context) { - t := time.Now() ctx.Data["PageIsCloudBrain"] = true ctx.Data["IsCreate"] = true ctx.Data["type"] = models.TypeCloudBrainOne @@ -497,7 +497,7 @@ func AiSafetyCreateForGetGPU(ctx *context.Context) { log.Info("GPUBaseDataSetUUID=" + setting.ModelSafetyTest.GPUBaseDataSetUUID) log.Info("GPUCombatDataSetName=" + setting.ModelSafetyTest.GPUCombatDataSetName) log.Info("GPUCombatDataSetUUID=" + setting.ModelSafetyTest.GPUCombatDataSetUUID) - var displayJobName = jobNamePrefixValid(cutString(ctx.User.Name, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:] + var displayJobName = cloudbrainService.GetDisplayJobName(ctx.User.Name) ctx.Data["display_job_name"] = displayJobName prepareCloudbrainOneSpecs(ctx) queuesDetail, _ := cloudbrain.GetQueuesDetail() @@ -514,12 +514,11 @@ func AiSafetyCreateForGetGPU(ctx *context.Context) { } func AiSafetyCreateForGetNPU(ctx *context.Context) { - t := time.Now() ctx.Data["PageIsCloudBrain"] = true ctx.Data["IsCreate"] = true ctx.Data["type"] = models.TypeCloudBrainTwo ctx.Data["compute_resource"] = models.NPUResource - var displayJobName = jobNamePrefixValid(cutString(ctx.User.Name, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:] + var displayJobName = cloudbrainService.GetDisplayJobName(ctx.User.Name) ctx.Data["display_job_name"] = displayJobName ctx.Data["datasetType"] = models.TypeCloudBrainTwo ctx.Data["BaseDataSetName"] = setting.ModelSafetyTest.NPUBaseDataSetName diff --git a/routers/repo/cloudbrain.go b/routers/repo/cloudbrain.go index 7d96d1b58..d3d76f440 100755 --- a/routers/repo/cloudbrain.go +++ b/routers/repo/cloudbrain.go @@ -15,6 +15,8 @@ import ( "time" "unicode/utf8" + cloudbrainService "code.gitea.io/gitea/services/cloudbrain" + "code.gitea.io/gitea/modules/urfs_client/urchin" "code.gitea.io/gitea/modules/dataset" @@ -92,28 +94,9 @@ func MustEnableCloudbrain(ctx *context.Context) { } } -func cutString(str string, lens int) string { - if len(str) < lens { - return str - } - return str[:lens] -} - -func jobNamePrefixValid(s string) string { - lowStr := strings.ToLower(s) - re := regexp.MustCompile(`[^a-z0-9_\\-]+`) - - removeSpecial := re.ReplaceAllString(lowStr, "") - - re = regexp.MustCompile(`^[_\\-]+`) - return re.ReplaceAllString(removeSpecial, "") - -} - func cloudBrainNewDataPrepare(ctx *context.Context, jobType string) error { ctx.Data["PageIsCloudBrain"] = true - t := time.Now() - var displayJobName = jobNamePrefixValid(cutString(ctx.User.Name, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:] + var displayJobName = cloudbrainService.GetDisplayJobName(ctx.User.Name) ctx.Data["display_job_name"] = displayJobName ctx.Data["command"] = cloudbrain.GetCloudbrainDebugCommand() @@ -696,7 +679,7 @@ func CloudBrainRestart(ctx *context.Context) { } else { if count >= 1 { log.Error("the user already has running or waiting task", ctx.Data["MsgID"]) - resultCode = "-1" + resultCode = "2" errorMsg = ctx.Tr("repo.cloudbrain.morethanonejob") break } @@ -759,43 +742,13 @@ func cloudBrainShow(ctx *context.Context, tpName base.TplName, jobType models.Jo return } if task.Status == string(models.JobWaiting) || task.Status == string(models.JobRunning) { - result, err := cloudbrain.GetJob(task.JobID) + task, err = cloudbrainTask.SyncCloudBrainOneStatus(task) if err != nil { log.Info("error:" + err.Error()) ctx.NotFound(ctx.Req.URL.RequestURI(), nil) return } - if result != nil { - jobRes, _ := models.ConvertToJobResultPayload(result.Payload) - taskRoles := jobRes.TaskRoles - taskRes, _ := models.ConvertToTaskPod(taskRoles[cloudbrain.SubTaskName].(map[string]interface{})) - ctx.Data["taskRes"] = taskRes - ctx.Data["ExitDiagnostics"] = taskRes.TaskStatuses[0].ExitDiagnostics - oldStatus := task.Status - task.Status = taskRes.TaskStatuses[0].State - task.ContainerIp = "" - task.ContainerID = taskRes.TaskStatuses[0].ContainerID - models.ParseAndSetDurationFromCloudBrainOne(jobRes, task) - - if task.DeletedAt.IsZero() { //normal record - if oldStatus != task.Status { - notification.NotifyChangeCloudbrainStatus(task, oldStatus) - } - err = models.UpdateJob(task) - if err != nil { - ctx.Data["error"] = err.Error() - return - } - } else { //deleted record - - } - - ctx.Data["result"] = jobRes - } else { - log.Info("error:" + err.Error()) - return - } } user, err := models.GetUserByID(task.UserID) @@ -889,7 +842,13 @@ func cloudBrainShow(ctx *context.Context, tpName base.TplName, jobType models.Jo func CloudBrainDebug(ctx *context.Context) { task := ctx.Cloudbrain debugUrl := setting.DebugServerHost + "jpylab_" + task.JobID + "_" + task.SubTaskName - ctx.Redirect(debugUrl) + if task.BootFile!=""{ + ctx.Redirect(getFileUrl(debugUrl,task.BootFile)) + + }else{ + ctx.Redirect(debugUrl) + } + } func prepareSpec4Show(ctx *context.Context, task *models.Cloudbrain) { diff --git a/routers/repo/cloudbrain_statistic.go b/routers/repo/cloudbrain_statistic.go index ceca2845b..2ec12cd41 100644 --- a/routers/repo/cloudbrain_statistic.go +++ b/routers/repo/cloudbrain_statistic.go @@ -8,7 +8,6 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" cloudbrainService "code.gitea.io/gitea/services/cloudbrain" ) @@ -23,9 +22,15 @@ func CloudbrainDurationStatisticHour() { now := time.Now() currentTime := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, now.Location()) if err == nil && len(recordDurationUpdateTime) > 0 { - statisticTime = time.Unix(int64(recordDurationUpdateTime[0].DateTime), 0) + statisticTime = time.Unix(int64(recordDurationUpdateTime[0].DateTime), 0).Add(+1 * time.Hour) } else { - statisticTime = currentTime.Add(-1 * time.Hour) + statisticTime = currentTime + } + deleteBeginTime := time.Unix(int64(recordDurationUpdateTime[0].DateTime), 0) + + err = models.DeleteCloudbrainDurationStatistic(timeutil.TimeStamp(deleteBeginTime.Unix()), timeutil.TimeStamp(currentTime.Unix())) + if err != nil { + log.Error("DeleteCloudbrainDurationStatistic failed", err) } for statisticTime.Before(currentTime) || statisticTime.Equal(currentTime) { @@ -35,13 +40,10 @@ func CloudbrainDurationStatisticHour() { } log.Info("summaryDurationStat count: %v", count) } -func UpdateDurationStatisticHistoryData() int64 { +func UpdateDurationStatisticHistoryData(beginTime time.Time, endTime time.Time) int64 { var count int64 - recordBeginTime, _ := time.ParseInLocation("2006-01-02 15:04:05", setting.Grampus.UsageRateBeginTime, time.Local) - now := time.Now() - currentTime := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, now.Location()) - statisticTime := recordBeginTime.Add(+1 * time.Hour) - + statisticTime := beginTime + currentTime := endTime for statisticTime.Before(currentTime) || statisticTime.Equal(currentTime) { countEach := summaryDurationStat(statisticTime) count += countEach @@ -105,13 +107,6 @@ func summaryDurationStat(statisticTime time.Time) int64 { for cardType, cardDuration := range CardTypes { cloudbrainTable := cloudbrainMap[centerCode+"/"+cardType] if cloudbrainTable != nil { - if _, err := models.GetDurationStatisticByDate(dayTime, hourTime, centerCode, cardType); err == nil { - if err := models.DeleteCloudbrainDurationStatisticHour(dayTime, hourTime, centerCode, cardType); err != nil { - log.Error("DeleteCloudbrainDurationStatisticHour failed: %v", err.Error()) - return 0 - } - } - if _, ok := cardsTotalDurationMap[cloudbrainTable.Cluster+"/"+centerCode+"/"+cardType]; !ok { cardsTotalDurationMap[cloudbrainTable.Cluster+"/"+centerCode+"/"+cardType] = 0 } @@ -137,12 +132,6 @@ func summaryDurationStat(statisticTime time.Time) int64 { } for key, cardsTotalDuration := range cardsTotalDurationMap { - if _, err := models.GetDurationStatisticByDate(dayTime, hourTime, strings.Split(key, "/")[1], strings.Split(key, "/")[2]); err == nil { - if err := models.DeleteCloudbrainDurationStatisticHour(dayTime, hourTime, strings.Split(key, "/")[1], strings.Split(key, "/")[2]); err != nil { - log.Error("DeleteCloudbrainDurationStatisticHour failed: %v", err.Error()) - return 0 - } - } cloudbrainDurationStat := models.CloudbrainDurationStatistic{ DateTime: dateTime, DayTime: dayTime, @@ -255,8 +244,22 @@ func getcloudBrainCenterCodeAndCardTypeInfo(ciTasks []*models.CloudbrainInfo, be } func CloudbrainUpdateHistoryData(ctx *context.Context) { - err := models.DeleteCloudbrainDurationStatistic() - count := UpdateDurationStatisticHistoryData() + beginTimeStr := ctx.QueryTrim("beginTime") + endTimeStr := ctx.QueryTrim("endTime") + var count int64 + var err error + if beginTimeStr != "" && endTimeStr != "" { + beginTime, _ := time.ParseInLocation("2006-01-02 15:04:05", beginTimeStr, time.Local) + endTime, _ := time.ParseInLocation("2006-01-02 15:04:05", endTimeStr, time.Local) + if time.Now().Before(endTime) { + endTime = time.Now() + } + beginTimeUnix := timeutil.TimeStamp(beginTime.Unix()) + endTimeUnix := timeutil.TimeStamp(endTime.Unix()) + + err = models.DeleteCloudbrainDurationStatistic(beginTimeUnix, endTimeUnix) + count = UpdateDurationStatisticHistoryData(beginTime.Add(+1*time.Hour), endTime) + } ctx.JSON(http.StatusOK, map[string]interface{}{ "message": 0, "count": count, diff --git a/routers/repo/grampus.go b/routers/repo/grampus.go index de7bb454d..8f3182758 100755 --- a/routers/repo/grampus.go +++ b/routers/repo/grampus.go @@ -10,7 +10,6 @@ import ( "path" "strconv" "strings" - "time" "code.gitea.io/gitea/modules/urfs_client/urchin" "code.gitea.io/gitea/routers/response" @@ -77,8 +76,7 @@ func GrampusTrainJobNPUNew(ctx *context.Context) { func grampusTrainJobNewDataPrepare(ctx *context.Context, processType string) error { ctx.Data["PageIsCloudBrain"] = true - t := time.Now() - var displayJobName = jobNamePrefixValid(cutString(ctx.User.Name, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:] + var displayJobName = cloudbrainService.GetDisplayJobName(ctx.User.Name) ctx.Data["display_job_name"] = displayJobName //get valid images diff --git a/routers/repo/modelarts.go b/routers/repo/modelarts.go index fabf7e555..b992734e4 100755 --- a/routers/repo/modelarts.go +++ b/routers/repo/modelarts.go @@ -15,6 +15,8 @@ import ( "time" "unicode/utf8" + cloudbrainService "code.gitea.io/gitea/services/cloudbrain" + "code.gitea.io/gitea/services/cloudbrain/cloudbrainTask" "code.gitea.io/gitea/modules/dataset" @@ -128,8 +130,7 @@ func NotebookNew(ctx *context.Context) { func notebookNewDataPrepare(ctx *context.Context) error { ctx.Data["PageIsCloudBrain"] = true - t := time.Now() - var displayJobName = jobNamePrefixValid(cutString(ctx.User.Name, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:] + var displayJobName = cloudbrainService.GetDisplayJobName(ctx.User.Name) ctx.Data["display_job_name"] = displayJobName attachs, err := models.GetModelArtsUserAttachments(ctx.User.ID) @@ -239,9 +240,9 @@ func Notebook2Create(ctx *context.Context, form auth.CreateModelArtsNotebookForm } if setting.ModelartsCD.Enabled { - err = modelarts_cd.GenerateNotebook(ctx, displayJobName, jobName, uuid, description, imageId, spec) + _, err = modelarts_cd.GenerateNotebook(ctx, displayJobName, jobName, uuid, description, imageId, spec, "",modelarts.AutoStopDurationMs) } else { - err = modelarts.GenerateNotebook2(ctx, displayJobName, jobName, uuid, description, imageId, spec) + _, err = modelarts.GenerateNotebook2(ctx, displayJobName, jobName, uuid, description, imageId, spec, "",modelarts.AutoStopDurationMs) } if err != nil { @@ -387,8 +388,33 @@ func NotebookDebug2(ctx *context.Context) { ctx.RenderWithErr(err.Error(), tplModelArtsNotebookIndex, nil) return } + if task.BootFile!=""{ + ctx.Redirect(getFileUrl(result.Url,task.BootFile) + "?token="+ result.Token) + }else{ + ctx.Redirect(result.Url + "?token=" + result.Token) + } + - ctx.Redirect(result.Url + "?token=" + result.Token) +} + +func getFileUrl(url string,filename string) string{ + middle:="" + if url[len(url)-3:]=="lab" || url[len(url)-4:]=="lab/" { + if url[len(url)-1] == '/' { + middle="tree/" + } else { + middle= "/tree/" + } + }else{ + if url[len(url)-1] == '/' { + middle = "lab/tree/" + } else { + middle= "/lab/tree/" + } + } + + + return url+middle+path.Base(filename) } func NotebookRestart(ctx *context.Context) { @@ -420,7 +446,8 @@ func NotebookRestart(ctx *context.Context) { } else { if count >= 1 { log.Error("the user already has running or waiting task", ctx.Data["MsgID"]) - errorMsg = "you have already a running or waiting task, can not create more" + resultCode="2" + errorMsg = ctx.Tr("repo.cloudbrain.morethanonejob") break } } @@ -714,8 +741,7 @@ func trainJobNewDataPrepare(ctx *context.Context) error { // return //} - t := time.Now() - var displayJobName = jobNamePrefixValid(cutString(ctx.User.Name, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:] + var displayJobName = cloudbrainService.GetDisplayJobName(ctx.User.Name) ctx.Data["display_job_name"] = displayJobName attachs, err := models.GetModelArtsTrainAttachments(ctx.User.ID) @@ -2351,8 +2377,7 @@ func inferenceJobNewDataPrepare(ctx *context.Context) error { ctx.Data["PageIsCloudBrain"] = true ctx.Data["newInference"] = true - t := time.Now() - var displayJobName = jobNamePrefixValid(cutString(ctx.User.Name, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:] + var displayJobName = cloudbrainService.GetDisplayJobName(ctx.User.Name) ctx.Data["display_job_name"] = displayJobName attachs, err := models.GetModelArtsTrainAttachments(ctx.User.ID) diff --git a/routers/repo/repo.go b/routers/repo/repo.go index 2c8c2f45b..4919b2487 100644 --- a/routers/repo/repo.go +++ b/routers/repo/repo.go @@ -414,7 +414,9 @@ func Action(ctx *context.Context) { var err error switch ctx.Params(":action") { case "watch": - err = models.WatchRepo(ctx.User.ID, ctx.Repo.Repository.ID, true) + err = models.WatchRepo(ctx.User.ID, ctx.Repo.Repository.ID, true, models.ReceiveAllNotification) + case "watch_but_reject": + err = models.WatchRepo(ctx.User.ID, ctx.Repo.Repository.ID, true, models.RejectAllNotification) case "unwatch": err = models.WatchRepo(ctx.User.ID, ctx.Repo.Repository.ID, false) case "star": diff --git a/routers/routes/routes.go b/routers/routes/routes.go index 8d5c79b9e..60f0365ea 100755 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -519,6 +519,7 @@ func RegisterRoutes(m *macaron.Macaron) { // r.Get("/feeds", binding.Bind(auth.FeedsForm{}), user.Feeds) m.Any("/activate", user.Activate, reqSignIn) m.Any("/activate_email", user.ActivateEmail) + m.Post("/update_email", bindIgnErr(auth.UpdateEmailForm{}), user.UpdateEmailPost) m.Get("/avatar/:username/:size", user.Avatar) m.Get("/email2user", user.Email2User) m.Get("/recover_account", user.ResetPasswd) diff --git a/routers/user/auth.go b/routers/user/auth.go index 57ffb1710..bf858706d 100755 --- a/routers/user/auth.go +++ b/routers/user/auth.go @@ -1413,6 +1413,34 @@ func SignUpPost(ctx *context.Context, cpt *captcha.Captcha, form auth.RegisterFo handleSignInFull(ctx, u, false, true) } +//update user emailAddress +func UpdateEmailPost(ctx *context.Context, form auth.UpdateEmailForm) { + newEmailAddress := ctx.Query("NewEmail") + if newEmailAddress == "" { + log.Error("please input the newEmail") + return + } + if used, _ := models.IsEmailUsed(newEmailAddress); used { + ctx.RenderWithErr(ctx.Tr("form.email_been_used"), TplActivate, &form) + return + } + user := ctx.User + email, err := models.GetEmailAddressByIDAndEmail(user.ID, user.Email) + if err != nil { + ctx.ServerError("GetEmailAddressByIDAndEmail failed", err) + return + } + err = email.UpdateEmailAddress(newEmailAddress) + if err != nil { + ctx.ServerError("UpdateEmailAddress failed", err) + return + } + ctx.Data["Email"] = newEmailAddress + ctx.User.Email = newEmailAddress + Activate(ctx) + +} + // Activate render activate user page func Activate(ctx *context.Context) { code := ctx.Query("code") diff --git a/services/cloudbrain/cloudbrainTask/notebook.go b/services/cloudbrain/cloudbrainTask/notebook.go new file mode 100644 index 000000000..6b2fcf707 --- /dev/null +++ b/services/cloudbrain/cloudbrainTask/notebook.go @@ -0,0 +1,362 @@ +package cloudbrainTask + +import ( + "fmt" + "net/http" + "path" + + "code.gitea.io/gitea/modules/modelarts" + "code.gitea.io/gitea/modules/modelarts_cd" + + "code.gitea.io/gitea/modules/git" + + "code.gitea.io/gitea/modules/cloudbrain" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/redis/redis_key" + "code.gitea.io/gitea/modules/redis/redis_lock" + "code.gitea.io/gitea/modules/storage" + "code.gitea.io/gitea/services/cloudbrain/resource" + "code.gitea.io/gitea/services/reward/point/account" + + "code.gitea.io/gitea/modules/setting" + cloudbrainService "code.gitea.io/gitea/services/cloudbrain" + repo_service "code.gitea.io/gitea/services/repository" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/context" + api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/util" +) + +const NoteBookExtension = ".ipynb" + +func FileNotebookCreate(ctx *context.Context, option api.CreateFileNotebookJobOption) { + + if ctx.Written() { + return + } + + if path.Ext(option.File) != NoteBookExtension { + ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.notebook_select_wrong"))) + return + } + + isNotebookFileExist, _ := isNoteBookFileExist(ctx, option) + if !isNotebookFileExist { + ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.notebook_file_not_exist"))) + return + } + + sourceRepo, err := models.GetRepositoryByOwnerAndName(option.OwnerName, option.ProjectName) + if err != nil { + ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.notebook_file_not_exist"))) + return + } + + permission, err := models.GetUserRepoPermission(sourceRepo, ctx.User) + if err != nil { + log.Error("Get permission failed", err) + ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.notebook_file_no_right"))) + return + } + + if !permission.CanRead(models.UnitTypeCode) { + ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.notebook_file_no_right"))) + return + } + + //create repo if not exist + repo, err := models.GetRepositoryByName(ctx.User.ID, setting.FileNoteBook.ProjectName) + if repo == nil { + repo, err = repo_service.CreateRepository(ctx.User, ctx.User, models.CreateRepoOptions{ + Name: setting.FileNoteBook.ProjectName, + Alias: "", + Description: "", + IssueLabels: "", + Gitignores: "", + License: "", + Readme: "Default", + IsPrivate: false, + AutoInit: true, + DefaultBranch: "master", + }) + } + if err != nil { + ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.failed_to_create_notebook_repo",setting.FileNoteBook.ProjectName))) + return + } + if option.Type <= 1 { + cloudBrainFileNoteBookCreate(ctx, option, repo, sourceRepo) + } else { + modelartsFileNoteBookCreate(ctx, option, repo, sourceRepo) + } + +} + +func cloudBrainFileNoteBookCreate(ctx *context.Context, option api.CreateFileNotebookJobOption, repo *models.Repository, sourceRepo *models.Repository) { + + displayJobName := cloudbrainService.GetDisplayJobName(ctx.User.Name) + jobName := util.ConvertDisplayJobNameToJobName(displayJobName) + jobType := string(models.JobTypeDebug) + + lock := redis_lock.NewDistributeLock(redis_key.CloudbrainBindingJobNameKey(fmt.Sprint(repo.ID), jobType, displayJobName)) + defer lock.UnLock() + isOk, err := lock.Lock(models.CloudbrainKeyDuration) + if !isOk { + log.Error("lock processed failed:%v", err, ctx.Data["MsgID"]) + ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.cloudbrain_samejob_err"))) + 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"]) + ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.cloudbrain_samejob_err"))) + return + } + } else { + if !models.IsErrJobNotExist(err) { + log.Error("system error, %v", err, ctx.Data["MsgID"]) + ctx.JSON(http.StatusOK, models.BaseErrorMessageApi("system error.")) + return + } + } + + count, err := GetNotFinalStatusTaskCount(ctx.User.ID, models.TypeCloudBrainOne, jobType) + if err != nil { + log.Error("GetCloudbrainCountByUserID failed:%v", err, ctx.Data["MsgID"]) + ctx.JSON(http.StatusOK, models.BaseErrorMessageApi("system error.")) + return + } else { + if count >= 1 { + log.Error("the user already has running or waiting task", ctx.Data["MsgID"]) + ctx.JSON(http.StatusOK,models.BaseMessageApi{ + Code: 2, + Message: ctx.Tr("repo.cloudbrain.morethanonejob"), + }) + return + } + } + + errStr := uploadCodeFile(sourceRepo, getCodePath(jobName), option.BranchName, option.File, jobName) + if errStr != "" { + ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.notebook_file_not_exist"))) + return + } + command := cloudbrain.GetCloudbrainDebugCommand() + specId := setting.FileNoteBook.SpecIdGPU + if option.Type == 0 { + specId = setting.FileNoteBook.SpecIdCPU + } + spec, err := resource.GetAndCheckSpec(ctx.User.ID, specId, models.FindSpecsOptions{ + JobType: models.JobType(jobType), + ComputeResource: models.GPU, + Cluster: models.OpenICluster, + AiCenterCode: models.AICenterOfCloudBrainOne}) + if err != nil || spec == nil { + ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("cloudbrain.wrong_specification"))) + return + } + + if !account.IsPointBalanceEnough(ctx.User.ID, spec.UnitPrice) { + log.Error("point balance is not enough,userId=%d specId=%d", ctx.User.ID, spec.ID) + ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("points.insufficient_points_balance"))) + return + } + ctx.Repo = &context.Repository{ + Repository: repo, + } + + req := cloudbrain.GenerateCloudBrainTaskReq{ + Ctx: ctx, + DisplayJobName: displayJobName, + JobName: jobName, + Image: setting.FileNoteBook.ImageGPU, + Command: command, + Uuids: "", + DatasetNames: "", + DatasetInfos: nil, + CodePath: storage.GetMinioPath(jobName, cloudbrain.CodeMountPath+"/"), + ModelPath: storage.GetMinioPath(jobName, cloudbrain.ModelMountPath+"/"), + BenchmarkPath: storage.GetMinioPath(jobName, cloudbrain.BenchMarkMountPath+"/"), + Snn4ImageNetPath: storage.GetMinioPath(jobName, cloudbrain.Snn4imagenetMountPath+"/"), + BrainScorePath: storage.GetMinioPath(jobName, cloudbrain.BrainScoreMountPath+"/"), + JobType: jobType, + Description: getDescription(option), + BranchName: option.BranchName, + BootFile: option.File, + Params: "{\"parameter\":[]}", + CommitID: "", + BenchmarkTypeID: 0, + BenchmarkChildTypeID: 0, + ResultPath: storage.GetMinioPath(jobName, cloudbrain.ResultPath+"/"), + Spec: spec, + } + + jobId, err := cloudbrain.GenerateTask(req) + if err != nil { + ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(err.Error())) + return + } + ctx.JSON(http.StatusOK, models.BaseMessageApi{ + Code: 0, + Message: jobId, + }) + +} + +func getCodePath(jobName string) string { + return setting.JobPath + jobName + cloudbrain.CodeMountPath +} + +func getDescription(option api.CreateFileNotebookJobOption) string { + return option.OwnerName + "/" + option.ProjectName + "/" + option.File +} + +func modelartsFileNoteBookCreate(ctx *context.Context, option api.CreateFileNotebookJobOption, repo *models.Repository, sourceRepo *models.Repository) { + displayJobName := cloudbrainService.GetDisplayJobName(ctx.User.Name) + jobName := util.ConvertDisplayJobNameToJobName(displayJobName) + + lock := redis_lock.NewDistributeLock(redis_key.CloudbrainBindingJobNameKey(fmt.Sprint(repo.ID), string(models.JobTypeDebug), displayJobName)) + isOk, err := lock.Lock(models.CloudbrainKeyDuration) + if !isOk { + log.Error("lock processed failed:%v", err, ctx.Data["MsgID"]) + ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.cloudbrain_samejob_err"))) + return + } + defer lock.UnLock() + + count, err := GetNotFinalStatusTaskCount(ctx.User.ID, models.TypeCloudBrainTwo, string(models.JobTypeDebug)) + + if err != nil { + log.Error("GetCloudbrainNotebookCountByUserID failed:%v", err, ctx.Data["MsgID"]) + + ctx.JSON(http.StatusOK, models.BaseErrorMessageApi("system error.")) + return + } else { + if count >= 1 { + log.Error("the user already has running or waiting task", ctx.Data["MsgID"]) + ctx.JSON(http.StatusOK,models.BaseMessageApi{ + Code: 2, + Message: ctx.Tr("repo.cloudbrain.morethanonejob"), + }) + return + } + } + + tasks, err := models.GetCloudbrainsByDisplayJobName(repo.ID, string(models.JobTypeDebug), displayJobName) + if err == nil { + if len(tasks) != 0 { + log.Error("the job name did already exist", ctx.Data["MsgID"]) + ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.cloudbrain_samejob_err"))) + return + } + } else { + if !models.IsErrJobNotExist(err) { + log.Error("system error, %v", err, ctx.Data["MsgID"]) + ctx.JSON(http.StatusOK, models.BaseErrorMessageApi("system error.")) + return + } + } + + err = downloadCode(sourceRepo, getCodePath(jobName), option.BranchName) + if err != nil { + ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("cloudbrain.load_code_failed"))) + return + } + + var aiCenterCode = models.AICenterOfCloudBrainTwo + var specId = setting.FileNoteBook.SpecIdNPU + if setting.ModelartsCD.Enabled { + aiCenterCode = models.AICenterOfChengdu + specId = setting.FileNoteBook.SpecIdNPUCD + } + spec, err := resource.GetAndCheckSpec(ctx.User.ID, specId, models.FindSpecsOptions{ + JobType: models.JobTypeDebug, + ComputeResource: models.NPU, + Cluster: models.OpenICluster, + AiCenterCode: aiCenterCode}) + if err != nil || spec == nil { + ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("cloudbrain.wrong_specification"))) + return + } + if !account.IsPointBalanceEnough(ctx.User.ID, spec.UnitPrice) { + log.Error("point balance is not enough,userId=%d specId=%d ", ctx.User.ID, spec.ID) + ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("points.insufficient_points_balance"))) + return + } + ctx.Repo = &context.Repository{ + Repository: repo, + } + + var jobId string + if setting.ModelartsCD.Enabled { + jobId, err = modelarts_cd.GenerateNotebook(ctx, displayJobName, jobName, "", getDescription(option), setting.FileNoteBook.ImageIdNPUCD, spec, option.File,modelarts.AutoStopDurationMs/4) + } else { + jobId, err = modelarts.GenerateNotebook2(ctx, displayJobName, jobName, "", getDescription(option), setting.FileNoteBook.ImageIdNPU, spec, option.File,modelarts.AutoStopDurationMs/4) + } + + if err != nil { + log.Error("GenerateNotebook2 failed, %v", err, ctx.Data["MsgID"]) + + ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(err.Error())) + + return + } + + ctx.JSON(http.StatusOK, models.BaseMessageApi{ + Code: 0, + Message: jobId, + }) + +} + +func isNoteBookFileExist(ctx *context.Context, option api.CreateFileNotebookJobOption) (bool, error) { + repoPathOfNoteBook := models.RepoPath(option.OwnerName, option.ProjectName) + + gitRepoOfNoteBook, err := git.OpenRepository(repoPathOfNoteBook) + if err != nil { + log.Error("RepoRef Invalid repo "+repoPathOfNoteBook, err.Error()) + return false, err + } + // We opened it, we should close it + defer func() { + // If it's been set to nil then assume someone else has closed it. + if gitRepoOfNoteBook != nil { + gitRepoOfNoteBook.Close() + } + }() + fileExist, err := fileExists(gitRepoOfNoteBook, option.File, option.BranchName) + if err != nil || !fileExist { + log.Error("Get file error:", err, ctx.Data["MsgID"]) + + return false, err + } + return true, nil +} + +func uploadCodeFile(repo *models.Repository, codePath string, branchName string, filePath string, jobName string) string { + err := downloadCode(repo, codePath, branchName) + if err != nil { + return "cloudbrain.load_code_failed" + } + + err = uploadOneFileToMinio(codePath, filePath, jobName, cloudbrain.CodeMountPath+"/") + if err != nil { + return "cloudbrain.load_code_failed" + } + return "" +} + +func fileExists(gitRepo *git.Repository, path string, branch string) (bool, error) { + + commit, err := gitRepo.GetBranchCommit(branch) + if err != nil { + return false, err + } + if _, err := commit.GetTreeEntryByPath(path); err != nil { + return false, err + } + return true, nil +} diff --git a/services/cloudbrain/cloudbrainTask/sync_status.go b/services/cloudbrain/cloudbrainTask/sync_status.go index 67dc4d3b7..973b9bbc2 100644 --- a/services/cloudbrain/cloudbrainTask/sync_status.go +++ b/services/cloudbrain/cloudbrainTask/sync_status.go @@ -1,20 +1,21 @@ package cloudbrainTask import ( - "net/http" - "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/cloudbrain" - "code.gitea.io/gitea/modules/httplib" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/notification" "code.gitea.io/gitea/modules/setting" + "net/http" + "strconv" ) var noteBookOKMap = make(map[int64]int, 20) +var noteBookFailMap = make(map[int64]int, 20) -//if a task notebook url can get two times, the notebook can browser. +//if a task notebook url can get successfulCount times, the notebook can browser. const successfulCount = 3 +const maxSuccessfulCount=10 func SyncCloudBrainOneStatus(task *models.Cloudbrain) (*models.Cloudbrain, error) { jobResult, err := cloudbrain.GetJob(task.JobID) @@ -62,21 +63,29 @@ func isNoteBookReady(task *models.Cloudbrain) bool { return true } noteBookUrl := setting.DebugServerHost + "jpylab_" + task.JobID + "_" + task.SubTaskName - r := httplib.Get(noteBookUrl) - res, err := r.Response() + res,err := http.Get(noteBookUrl) if err != nil { return false } + log.Info("notebook success count:"+strconv.Itoa(noteBookOKMap[task.ID])+",fail count:"+strconv.Itoa(noteBookFailMap[task.ID])) if res.StatusCode == http.StatusOK { count := noteBookOKMap[task.ID] - if count < successfulCount-1 { + if count==0{ //如果是第一次成功,把失败数重置为0 + noteBookFailMap[task.ID]=0 + } + + if count < successfulCount-1 || (noteBookFailMap[task.ID]==0 && count < maxSuccessfulCount-1) { noteBookOKMap[task.ID] = count + 1 return false } else { + log.Info("notebook success count:"+strconv.Itoa(count)+",fail count:"+strconv.Itoa(noteBookFailMap[task.ID])) delete(noteBookOKMap, task.ID) + delete(noteBookFailMap, task.ID) return true } + }else{ + noteBookFailMap[task.ID]+=1 } return false diff --git a/services/cloudbrain/cloudbrainTask/train.go b/services/cloudbrain/cloudbrainTask/train.go index 8e4673d66..00d01a7ce 100644 --- a/services/cloudbrain/cloudbrainTask/train.go +++ b/services/cloudbrain/cloudbrainTask/train.go @@ -810,6 +810,18 @@ func uploadCodeToMinio(codePath, jobName, parentDir string) error { return nil } +func uploadOneFileToMinio(codePath, filePath, jobName, parentDir string) error { + destObject := setting.CBCodePathPrefix + jobName + parentDir + path.Base(filePath) + sourceFile := codePath + "/" + filePath + err := storage.Attachments.UploadObject(destObject, sourceFile) + if err != nil { + log.Error("UploadObject(%s) failed: %s", filePath, err.Error()) + return err + } + return nil + +} + func readDir(dirname string) ([]os.FileInfo, error) { f, err := os.Open(dirname) if err != nil { diff --git a/services/cloudbrain/util.go b/services/cloudbrain/util.go index dc9177ecf..0a3096e3f 100644 --- a/services/cloudbrain/util.go +++ b/services/cloudbrain/util.go @@ -1,7 +1,11 @@ package cloudbrain import ( + "regexp" + "strconv" "strings" + "time" + "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/context" @@ -33,6 +37,28 @@ func GetAiCenterShow(aiCenter string, ctx *context.Context) string { } +func GetDisplayJobName(username string) string { + t := time.Now() + return jobNamePrefixValid(cutString(username, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:] +} + +func cutString(str string, lens int) string { + if len(str) < lens { + return str + } + return str[:lens] +} + +func jobNamePrefixValid(s string) string { + lowStr := strings.ToLower(s) + re := regexp.MustCompile(`[^a-z0-9_\\-]+`) + + removeSpecial := re.ReplaceAllString(lowStr, "") + + re = regexp.MustCompile(`^[_\\-]+`) + return re.ReplaceAllString(removeSpecial, "") +} + func GetAiCenterInfoByCenterCode(aiCenterCode string) *setting.C2NetSequenceInfo { if setting.AiCenterCodeAndNameMapInfo != nil { if info, ok := setting.AiCenterCodeAndNameMapInfo[aiCenterCode]; ok { diff --git a/templates/admin/cloudbrain/list.tmpl b/templates/admin/cloudbrain/list.tmpl index 20e704a4d..94f80c0fa 100755 --- a/templates/admin/cloudbrain/list.tmpl +++ b/templates/admin/cloudbrain/list.tmpl @@ -238,6 +238,7 @@ {{$.i18n.Tr "repo.debug"}} {{else}} + {{if not .BootFile}} {{end}} + {{end}} {{end}} diff --git a/templates/repo/cloudbrain/inference/show.tmpl b/templates/repo/cloudbrain/inference/show.tmpl index aee08d659..b86accead 100644 --- a/templates/repo/cloudbrain/inference/show.tmpl +++ b/templates/repo/cloudbrain/inference/show.tmpl @@ -362,7 +362,7 @@ - 创建人 + {{$.i18n.Tr "repo.cloudbrain_creator"}} @@ -444,6 +444,7 @@
{{.BranchName}} + {{SubStr .CommitID 0 10}}
diff --git a/templates/repo/cloudbrain/show.tmpl b/templates/repo/cloudbrain/show.tmpl index cca85fb32..27c3cc556 100755 --- a/templates/repo/cloudbrain/show.tmpl +++ b/templates/repo/cloudbrain/show.tmpl @@ -337,6 +337,7 @@
{{.BranchName}} + {{SubStr .CommitID 0 10}}
diff --git a/templates/repo/cloudbrain/trainjob/show.tmpl b/templates/repo/cloudbrain/trainjob/show.tmpl index 75cad03b4..69bec19e7 100644 --- a/templates/repo/cloudbrain/trainjob/show.tmpl +++ b/templates/repo/cloudbrain/trainjob/show.tmpl @@ -410,6 +410,7 @@
{{.BranchName}} + {{SubStr .CommitID 0 10}}
diff --git a/templates/repo/debugjob/index.tmpl b/templates/repo/debugjob/index.tmpl index 20aacfb01..7345fa9bc 100755 --- a/templates/repo/debugjob/index.tmpl +++ b/templates/repo/debugjob/index.tmpl @@ -221,7 +221,7 @@ + data-jobid="{{.Cloudbrain.ID}}" data-resource="{{.ComputeResource}}" data-bootfile="{{.BootFile}}"> {{.Status}} @@ -266,6 +266,7 @@ {{$.i18n.Tr "repo.debug"}}
{{else}} + {{if not .BootFile}} {{end}} + {{end}} {{else}} {{if eq .Status "RUNNING" "WAITING" "CREATING" "STARTING"}} @@ -294,7 +296,9 @@ + data-jobid="{{.Cloudbrain.ID}}" + {{if .BootFile}}data-bootfile="{{.BootFile}}"{{end}}> + {{$.i18n.Tr "repo.stop"}} {{else}} @@ -322,6 +326,7 @@ {{end}} + {{if not .BootFile}}
+ {{end}} diff --git a/templates/repo/grampus/trainjob/show.tmpl b/templates/repo/grampus/trainjob/show.tmpl index e8d4082f4..9d46a5256 100755 --- a/templates/repo/grampus/trainjob/show.tmpl +++ b/templates/repo/grampus/trainjob/show.tmpl @@ -422,6 +422,7 @@
{{.BranchName}} + {{SubStr .CommitID 0 10}}
diff --git a/templates/repo/header.tmpl b/templates/repo/header.tmpl index cb83bebe7..5bac6504c 100755 --- a/templates/repo/header.tmpl +++ b/templates/repo/header.tmpl @@ -51,6 +51,49 @@ {{if not .IsBeingCreated}}
+
+
+ {{if $.IsWatchingRepo}}{{$.i18n.Tr "repo.watched"}}{{else}}{{$.i18n.Tr "repo.notWatched"}}{{end}} + + +
+ + {{.NumWatches}} + +
+
{{$.CsrfTokenHtml}}
@@ -90,7 +133,7 @@ {{end}}
{{if not .Repository.IsBeingCreated}} - +
+ +
{{template "base/footer" .}} + diff --git a/templates/user/dashboard/cloudbrains.tmpl b/templates/user/dashboard/cloudbrains.tmpl index a42dbdda8..9af17fb54 100755 --- a/templates/user/dashboard/cloudbrains.tmpl +++ b/templates/user/dashboard/cloudbrains.tmpl @@ -124,7 +124,8 @@ style="width: 8% !important;"> + data-jobid="{{$JobID}}" data-version="{{.VersionName}}" + data-bootfile="{{.BootFile}}"> {{.Status}} @@ -185,7 +186,6 @@ {{.Repo.OwnerName}}/{{.Repo.Alias}}
-
{{if eq .JobType "DEBUG"}}
@@ -199,6 +199,7 @@ {{$.i18n.Tr "repo.debug"}} {{else}} + {{if not .BootFile}} {{end}} + {{end}}
{{end}} @@ -228,7 +230,7 @@ + data-jobid="{{$JobID}}" data-bootfile="{{.BootFile}}"> {{$.i18n.Tr "repo.stop"}} @@ -236,7 +238,7 @@ + data-jobid="{{$JobID}}" data-version="{{.VersionName}}" data-bootfile="{{.BootFile}}"> {{$.i18n.Tr "repo.stop"}} {{end}} diff --git a/web_src/js/features/cloudrbanin.js b/web_src/js/features/cloudrbanin.js index d0c58bf3f..67166a67c 100644 --- a/web_src/js/features/cloudrbanin.js +++ b/web_src/js/features/cloudrbanin.js @@ -24,6 +24,7 @@ export default async function initCloudrain() { const repoPath = job.dataset.repopath; // const computeResource = job.dataset.resource const versionname = job.dataset.version; + const bootfile = job.dataset.bootfile; const status_text = $(`#${ID}-text`).text(); const finalState = [ "STOPPED", @@ -99,11 +100,16 @@ export default async function initCloudrain() { "SUCCEEDED", ].includes(status) ) { - $("#ai-debug-" + ID) - .removeClass("disabled") - .addClass("blue") - .text(debug_again_button) - .css("margin", "0"); + if (!bootfile) { + $("#ai-debug-" + ID) + .removeClass("disabled") + .addClass("blue") + .text(debug_again_button) + .css("margin", "0"); + } else { + $("#ai-debug-" + ID).remove() + } + } if (["RUNNING", "WAITING"].includes(status)) { $("#ai-stop-" + ID) @@ -289,7 +295,7 @@ export default async function initCloudrain() { assertDelete(this); } }); - function stopDebug(ID, stopUrl) { + function stopDebug(ID, stopUrl,bootFile) { $.ajax({ type: "POST", url: stopUrl, @@ -301,11 +307,15 @@ export default async function initCloudrain() { .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"); + if (!bootFile) { + $("#ai-debug-" + ID) + .removeClass("disabled") + .addClass("blue") + .text(debug_again_button) + .css("margin", "0"); + } else { + $("#ai-debug-" + ID).remove() + } $("#ai-image-" + ID) .removeClass("blue") .addClass("disabled"); @@ -344,7 +354,8 @@ export default async function initCloudrain() { $(".ui.basic.ai_stop").click(function () { const ID = this.dataset.jobid; const repoPath = this.dataset.repopath; - stopDebug(ID, repoPath); + const bootFile = this.dataset.bootfile + stopDebug(ID, repoPath,bootFile); }); function stopVersion(version_name, ID, repoPath) { diff --git a/web_src/less/openi.less b/web_src/less/openi.less index 5ce8dcbab..083d5e702 100644 --- a/web_src/less/openi.less +++ b/web_src/less/openi.less @@ -1301,3 +1301,17 @@ i.SUCCEEDED { max-height: 500px; overflow: auto; } +.chang-email .content { + display: block; + width: 100%; + font-size: 1em; + line-height: 1.4; + padding: 1.5rem; + background: #fff; +} +.chang-email .actions { + background: #f9fafb; + padding: 1rem 1rem; + border-top: 1px solid rgba(34,36,38,.15); + text-align: right; +} \ No newline at end of file diff --git a/web_src/vuepages/apis/modules/notobook.js b/web_src/vuepages/apis/modules/notobook.js new file mode 100644 index 000000000..4c59a253b --- /dev/null +++ b/web_src/vuepages/apis/modules/notobook.js @@ -0,0 +1,47 @@ +import service from "../service"; + +// Notebook新建页面需要的信息 +export const getFileNotebook = () => { + return service({ + url: "/api/v1/file_notebook", + method: "get", + params: {}, + }); +}; + +// Notebook新建调试任务 +// type, file, branch_name, owner_name, project_name +export const createNotebook = (data) => { + return service({ + url: "/api/v1/file_notebook/create", + method: "post", + data, + params: {}, + }); +}; + +// Notebook获取云脑I调试任务状态 +export const getCb1Notebook = (path,jobid) => { + return service({ + url: `/api/v1/${path}/cloudbrain/${jobid}`, + method: "get", + params: {}, + }); +}; + +// Notebook获取云脑I调试任务状态 +export const getCb2Notebook = (path,jobid) => { + return service({ + url: `/api/v1/${path}/modelarts/notebook/${jobid}`, + method: "get", + params: {}, + }); +}; + +export const stopNotebook = (url) => { + return service({ + url: url, + method: "post", + params: {}, + }); + }; \ No newline at end of file diff --git a/web_src/vuepages/apis/service.js b/web_src/vuepages/apis/service.js index 292b9ef78..c676a7d18 100644 --- a/web_src/vuepages/apis/service.js +++ b/web_src/vuepages/apis/service.js @@ -2,7 +2,6 @@ import axios from 'axios'; const service = axios.create({ baseURL: '/', - timeout: 20000, }); service.interceptors.request.use((config) => { diff --git a/web_src/vuepages/langs/config/en-US.js b/web_src/vuepages/langs/config/en-US.js index 0d30c6578..0488d682d 100644 --- a/web_src/vuepages/langs/config/en-US.js +++ b/web_src/vuepages/langs/config/en-US.js @@ -157,7 +157,7 @@ const en = { computeCluster: 'Compute Cluster', resourceSpecification: 'Resource Specification', lastUpdateTime: 'Last Update Time', - resSceneDeleteConfirm: 'Are you sure to delete the current Resource Scene?', + resSceneDeleteConfirm: 'Are you sure to delete the current Resource Scene?', resourceSpecificationIsAvailable: 'Specification Is Available', resourceSpecificationIsAvailableAll: 'Specification Is Available(All)', available: 'Available', @@ -192,7 +192,35 @@ const en = { dataDesensitizationModelExperience:'Data desensitization model experience', dataDesensitizationModelDesc:'Use AI technology to desensitize the face and license plate number in the picture. For more information about this model, please visit the project', limitFilesUpload:'Only jpg/jpeg/png files can be uploaded', - limitSizeUpload:'The size of the uploaded file cannot exceed 20M!', + limitSizeUpload: 'The size of the uploaded file cannot exceed 20M!', + notebook: { + createNewNotebook: "Create new notebook debug task", + sameTaskTips1: "You have created an", + sameTaskTips2: "equivalent task", + sameTaskTips3: "that is waiting or running, please wait for the task to finish before creating it.", + sameTaskTips4: "You can view all your Cloudbrain tasks in", + sameTaskTips5: "Home", + sameTaskTips6: "Cloudbrain Task", + sameTaskTips7: "", + cpuEnv: "CPU Environment", + gpuEnv: "GPU Environment", + npuEnv: "NPU environment", + newTask: "Create new task", + noQuene: "The current resources are sufficient and no tasks are queued", + queneTips1: "There are currently", + queneTips2: "tasks queued", + watiResource: "Waiting for resources to be allocated, please be patient", + debug: "Debug", + stop: "Stop", + stopping: "Stopping", + notebookRunning: "The debugging environment has been started, and it will automatically close after 4 hours ", + stopSuccess: "Stop task succeeded", + specification: "Specification", + graphicMemory: "Graphic Memory", + memory: "Memory", + sharedMemory: "Shared Memory", + tips: 'The newly created debugging task will be placed in the project openi-notebook under your name. If there is no such project, the system will automatically create a new one.' + }, modelManage: { modelManage: 'Model management', modelName: 'Model name', @@ -200,7 +228,7 @@ const en = { local: 'Local', online: 'Online', createModel: 'Create Model', - importLocalModel: 'Import Lacal Model', + importLocalModel: 'Import Local Model', importOnlineModel: 'Import Online Model', modifyModelInfo: 'Modify model information', addModelFiles: 'Add model files', diff --git a/web_src/vuepages/langs/config/zh-CN.js b/web_src/vuepages/langs/config/zh-CN.js index 88c953faf..1d915749e 100644 --- a/web_src/vuepages/langs/config/zh-CN.js +++ b/web_src/vuepages/langs/config/zh-CN.js @@ -1,198 +1,227 @@ const zh = { - loading: '加载中...', - noData: '暂无数据', - date: '日期', + loading: "加载中...", + noData: "暂无数据", + date: "日期", - confirm: '确定', - cancel: '取消', - confirm1: '确认', - pleaseCompleteTheInformationFirst: '请先完善信息!', - submittedSuccessfully: '提交成功!', - submittedFailed: '提交失败!', - operation: '操作', - edit: '修改', - delete: '删除', - tips: '提示', + confirm: "确定", + cancel: "取消", + confirm1: "确认", + pleaseCompleteTheInformationFirst: "请先完善信息!", + submittedSuccessfully: "提交成功!", + submittedFailed: "提交失败!", + operation: "操作", + edit: "修改", + delete: "删除", + tips: "提示", - accomplishTask: '积分任务', - adminOperate: '管理员操作', - runCloudBrainTask: '运行云脑任务', - operating: '消耗中', - succeeded: '已完成', - debugTask: '调试任务', - trainTask: '训练任务', - inferenceTask: '推理任务', - benchmarkTask: '评测任务', - createPublicProject: '创建公开项目', - dailyPutforwardTasks: '每日提出任务', - dailyPR: '每日提出PR', - comment: '发表评论', - uploadDatasetFile: '上传数据集文件', - importNewModel: '导入新模型', - completeWechatCodeScanningVerification: '完成微信扫码验证', - dailyRunCloudbrainTasks: '每日运行云脑任务', - datasetRecommendedByThePlatform: '数据集被平台推荐', - submitNewPublicImage: '提交新公开镜像', - imageRecommendedByThePlatform: '镜像被平台推荐', - firstChangeofAvatar: '首次更换头像', - dailyCommit: '每日commit', - calcPointDetails: '算力积分明细', - calcPointAcquisitionInstructions: '积分获取说明', - CurrAvailableCalcPoints: '当前可用算力积分(分)', - totalGainCalcPoints: '总获取算力积分(分)', - totalConsumeCalcPoints: '总消耗算力积分(分)', - gainDetail: '获取明细', - consumeDetail: '消耗明细', - serialNumber: '流水号', - time: '时间', - scene: '场景', - behaviorOfPoint: '积分行为', - explanation: '说明', - points: '积分', - status: '状态', - runTime: '运行时长', - taskName: '任务名称', + accomplishTask: "积分任务", + adminOperate: "管理员操作", + runCloudBrainTask: "运行云脑任务", + operating: "消耗中", + succeeded: "已完成", + debugTask: "调试任务", + trainTask: "训练任务", + inferenceTask: "推理任务", + benchmarkTask: "评测任务", + createPublicProject: "创建公开项目", + dailyPutforwardTasks: "每日提出任务", + dailyPR: "每日提出PR", + comment: "发表评论", + uploadDatasetFile: "上传数据集文件", + importNewModel: "导入新模型", + completeWechatCodeScanningVerification: "完成微信扫码验证", + dailyRunCloudbrainTasks: "每日运行云脑任务", + datasetRecommendedByThePlatform: "数据集被平台推荐", + submitNewPublicImage: "提交新公开镜像", + imageRecommendedByThePlatform: "镜像被平台推荐", + firstChangeofAvatar: "首次更换头像", + dailyCommit: "每日commit", + calcPointDetails: "算力积分明细", + calcPointAcquisitionInstructions: "积分获取说明", + CurrAvailableCalcPoints: "当前可用算力积分(分)", + totalGainCalcPoints: "总获取算力积分(分)", + totalConsumeCalcPoints: "总消耗算力积分(分)", + gainDetail: "获取明细", + consumeDetail: "消耗明细", + serialNumber: "流水号", + time: "时间", + scene: "场景", + behaviorOfPoint: "积分行为", + explanation: "说明", + points: "积分", + status: "状态", + runTime: "运行时长", + taskName: "任务名称", - createdRepository: '创建了项目', - repositoryWasDel: '项目已删除', - openedIssue: '创建了任务', - createdPullRequest: '创建了合并请求', - commentedOnIssue: '评论了任务', - uploadDataset: '上传了数据集文件', - createdNewModel: '导入了新模型', - firstBindingWechatRewards: '首次绑定微信奖励', - created: '创建了', - type: '类型', - dataset: '数据集', - setAsRecommendedDataset: '被设置为推荐数据集', - committedImage: '提交了镜像', - image: '镜像', - setAsRecommendedImage: '被设置为推荐镜像', - updatedAvatar: '更新了头像', - pushedBranch: '推送了{branch}分支代码到', - deleteBranch: '从{repo}删除分支{branch}', - pushedTag: '推送了标签{tag}到', - deleteTag: '从{repo}删除了标签{tag}', - dailyMaxTips: '达到每日上限积分,不能拿满分', - memory: '内存', - sharedMemory: '共享内存', - ';': ';', + createdRepository: "创建了项目", + repositoryWasDel: "项目已删除", + openedIssue: "创建了任务", + createdPullRequest: "创建了合并请求", + commentedOnIssue: "评论了任务", + uploadDataset: "上传了数据集文件", + createdNewModel: "导入了新模型", + firstBindingWechatRewards: "首次绑定微信奖励", + created: "创建了", + type: "类型", + dataset: "数据集", + setAsRecommendedDataset: "被设置为推荐数据集", + committedImage: "提交了镜像", + image: "镜像", + setAsRecommendedImage: "被设置为推荐镜像", + updatedAvatar: "更新了头像", + pushedBranch: "推送了{branch}分支代码到", + deleteBranch: "从{repo}删除分支{branch}", + pushedTag: "推送了标签{tag}到", + deleteTag: "从{repo}删除了标签{tag}", + dailyMaxTips: "达到每日上限积分,不能拿满分", + memory: "内存", + sharedMemory: "共享内存", + ";": ";", - noPointGainRecord: '还没有积分获取记录', - noPointConsumeRecord: '还没有积分消耗记录', + noPointGainRecord: "还没有积分获取记录", + noPointConsumeRecord: "还没有积分消耗记录", resourcesManagement: { - OpenI: '启智集群', - C2Net: '智算集群', - OpenIOne: '云脑一', - OpenITwo: '云脑二', - OpenIChengdu: '启智成都智算', - chengduCenter: '成都智算', - pclcci: '鹏城云计算所', - hefeiCenter: '合肥类脑类脑智能开放平台', - xuchangCenter: '中原人工智能计算中心', - willOnShelf: '待上架', - onShelf: '已上架', - offShelf: '已下架', - toOnShelf: '上架', - toOffShelf: '下架', - toSetPriceAndOnShelf: '定价上架', - status: '状态', - allStatus: '全部状态', - syncAiNetwork: '同步智算网络', - resQueue: '资源池(队列)', - allResQueue: '全部资源池(队列)', - addResQueue: '新建资源池(队列)', - addResQueueBtn: '新增资源池', - editResQueue: '修改资源池(队列)', - resQueueName: '资源池(队列)名称', - whichCluster: '所属集群', - allCluster: '全部集群', - aiCenter: '智算中心', - aiCenterID: '智算中心ID', - allAiCenter: '全部智算中心', - computeResource: '计算资源', - allComputeResource: '全部计算资源', - accCardType: '卡类型', - allAccCardType: '全部卡类型', - cardsTotalNum: '卡数', - accCardsNum: '卡数', - remark: '备注', - pleaseEnterRemark: '请输入备注(最大长度不超过255)', - pleaseEnterPositiveIntegerCardsTotalNum: '请输入正整数的卡数!', - addResSpecificationAndPriceInfo: '新增资源规格和单价信息', - addResSpecificationBtn: '新增资源规格', - editResSpecificationAndPriceInfo: '修改资源规格和单价信息', - resSpecificationAndPriceManagement: '资源规格单价管理', - sourceSpecCode: '对应资源编码', - sourceSpecCodeTips: '云脑II需要填写对应的资源编码', - sourceSpecId: '智算网络资源规格ID', - cpuNum: 'CPU数', - gpuMem: '显存', - mem: '内存', - shareMem: '共享内存', - unitPrice: '单价', - point_hr: '积分/时', - node: '节点', - free: '免费', - onShelfConfirm: '请确认上架该规格?', - offShelfConfirm: '请确认下架该规格?', - onShelfCode1001: '上架失败,资源池(队列)不可用。', - onShelfCode1003: '上架失败,资源规格不可用。', - offShelfDlgTip1: '当前资源规格已在以下场景中使用:', - offShelfDlgTip2: '请确认进行下架操作?', - resSceneManagement: '算力资源应用场景管理', - addResScene: '新建算力资源应用场景', - addResSceneBtn: '新增应用场景', - editResScene: '修改算力资源应用场景', - resSceneName: '应用场景名称', - jobType: '任务类型', - allJobType: '全部任务类型', - isExclusive: '是否专属', - allExclusiveAndCommonUse: '全部专属和通用', - exclusive: '专属', - commonUse: '通用', - exclusiveOrg: '专属组织', - exclusiveOrgTips: '多个组织名之间用英文分号隔开', - computeCluster: '算力集群', - resourceSpecification: '资源规格', - lastUpdateTime: '最后更新时间', - resSceneDeleteConfirm: '是否确认删除当前应用场景?', - resourceSpecificationIsAvailable: '资源规格是否可用', - resourceSpecificationIsAvailableAll: '资源规格是否可用(全部)', - available: '可用', - notAvailable: '不可用', + OpenI: "启智集群", + C2Net: "智算集群", + OpenIOne: "云脑一", + OpenITwo: "云脑二", + OpenIChengdu: "启智成都智算", + chengduCenter: "成都智算", + pclcci: "鹏城云计算所", + hefeiCenter: "合肥类脑类脑智能开放平台", + xuchangCenter: "中原人工智能计算中心", + willOnShelf: "待上架", + onShelf: "已上架", + offShelf: "已下架", + toOnShelf: "上架", + toOffShelf: "下架", + toSetPriceAndOnShelf: "定价上架", + status: "状态", + allStatus: "全部状态", + syncAiNetwork: "同步智算网络", + resQueue: "资源池(队列)", + allResQueue: "全部资源池(队列)", + addResQueue: "新建资源池(队列)", + addResQueueBtn: "新增资源池", + editResQueue: "修改资源池(队列)", + resQueueName: "资源池(队列)名称", + whichCluster: "所属集群", + allCluster: "全部集群", + aiCenter: "智算中心", + aiCenterID: "智算中心ID", + allAiCenter: "全部智算中心", + computeResource: "计算资源", + allComputeResource: "全部计算资源", + accCardType: "卡类型", + allAccCardType: "全部卡类型", + cardsTotalNum: "卡数", + accCardsNum: "卡数", + remark: "备注", + pleaseEnterRemark: "请输入备注(最大长度不超过255)", + pleaseEnterPositiveIntegerCardsTotalNum: "请输入正整数的卡数!", + addResSpecificationAndPriceInfo: "新增资源规格和单价信息", + addResSpecificationBtn: "新增资源规格", + editResSpecificationAndPriceInfo: "修改资源规格和单价信息", + resSpecificationAndPriceManagement: "资源规格单价管理", + sourceSpecCode: "对应资源编码", + sourceSpecCodeTips: "云脑II需要填写对应的资源编码", + sourceSpecId: "智算网络资源规格ID", + cpuNum: "CPU数", + gpuMem: "显存", + mem: "内存", + shareMem: "共享内存", + unitPrice: "单价", + point_hr: "积分/时", + node: "节点", + free: "免费", + onShelfConfirm: "请确认上架该规格?", + offShelfConfirm: "请确认下架该规格?", + onShelfCode1001: "上架失败,资源池(队列)不可用。", + onShelfCode1003: "上架失败,资源规格不可用。", + offShelfDlgTip1: "当前资源规格已在以下场景中使用:", + offShelfDlgTip2: "请确认进行下架操作?", + resSceneManagement: "算力资源应用场景管理", + addResScene: "新建算力资源应用场景", + addResSceneBtn: "新增应用场景", + editResScene: "修改算力资源应用场景", + resSceneName: "应用场景名称", + jobType: "任务类型", + allJobType: "全部任务类型", + isExclusive: "是否专属", + allExclusiveAndCommonUse: "全部专属和通用", + exclusive: "专属", + commonUse: "通用", + exclusiveOrg: "专属组织", + exclusiveOrgTips: "多个组织名之间用英文分号隔开", + computeCluster: "算力集群", + resourceSpecification: "资源规格", + lastUpdateTime: "最后更新时间", + resSceneDeleteConfirm: "是否确认删除当前应用场景?", + resourceSpecificationIsAvailable: "资源规格是否可用", + resourceSpecificationIsAvailableAll: "资源规格是否可用(全部)", + available: "可用", + notAvailable: "不可用", }, user: { - inviteFriends: '邀请好友', - inviteFriendsTips: '复制二维码或者注册邀请链接分享给好友', - clickToViewTheEventDetails: '点击查看活动详情', - copyRegistrationInvitationLink: '复制注册邀请链接', - registrationAdress: '注册地址:', - recommender: '推荐人:', - invitedFriends: '已邀请好友', - registrationTime: '注册时间', - theSharedContentHasBeenCopiedToTheClipboard: '分享内容已复制到剪切板', - copyError: '复制错误', - Activated: '已激活', - notActive: '未激活', + inviteFriends: "邀请好友", + inviteFriendsTips: "复制二维码或者注册邀请链接分享给好友", + clickToViewTheEventDetails: "点击查看活动详情", + copyRegistrationInvitationLink: "复制注册邀请链接", + registrationAdress: "注册地址:", + recommender: "推荐人:", + invitedFriends: "已邀请好友", + registrationTime: "注册时间", + theSharedContentHasBeenCopiedToTheClipboard: "分享内容已复制到剪切板", + copyError: "复制错误", + Activated: "已激活", + notActive: "未激活", + }, + tranformImageFailed: "图片脱敏失败", + originPicture: "原始图片", + desensitizationPicture: "脱敏图片", + desensitizationObject: "脱敏对象", + example: "示例", + startDesensitization: "开始处理", + all: "全部", + onlyFace: "仅人脸", + onlyLicensePlate: "仅车牌", + dragThePictureHere: "拖动图片到这里", + or: "或", + clickUpload: "点击上传", + dataDesensitizationModelExperience: "数据脱敏模型体验", + dataDesensitizationModelDesc: + "利用人工智能AI技术,把图片中的人脸、车牌号码进行脱敏处理。该模型更多信息请访问项目", + limitFilesUpload: "只能上传 jpg/jpeg/png 格式的文件", + limitSizeUpload: "上传文件大小不能超过 20M !", + notebook: { + createNewNotebook: "新建Notebook调试任务", + sameTaskTips1: "您已经有", + sameTaskTips2: "同类任务", + sameTaskTips3: "正在等待或运行中,请等待任务结束再创建", + sameTaskTips4: "可以在", + sameTaskTips5: "个人中心", + sameTaskTips6: "云脑任务", + sameTaskTips7: "查看您所有的云脑任务。", + cpuEnv: "CPU 环境", + gpuEnv: "GPU 环境", + npuEnv: "NPU 环境", + newTask: "新建任务", + noQuene: "当前资源充足,没有任务排队", + queneTips1: "当前有", + queneTips2: "个任务正在排队", + watiResource: "正在等待分配资源,请耐心等待", + debug: "调试", + stop: "停止", + stopping: "停止中", + notebookRunning: "调试环境已启动,单次连接 4 小时后自动关闭", + stopSuccess: "停止任务成功", + specification: "规格", + graphicMemory: "显存", + memory: "内存", + sharedMemory: "共享内存", + tips:'本次新建的调试任务会放在您名下项目openi-notebook中,如果没有该项目系统会自动新建一个。' }, - tranformImageFailed:'图片脱敏失败', - originPicture:'原始图片', - desensitizationPicture:'脱敏图片', - desensitizationObject:'脱敏对象', - example:'示例', - startDesensitization:'开始处理', - all:'全部', - onlyFace:'仅人脸', - onlyLicensePlate:'仅车牌', - dragThePictureHere:'拖动图片到这里', - or:'或', - clickUpload:'点击上传', - dataDesensitizationModelExperience:'数据脱敏模型体验', - dataDesensitizationModelDesc:'利用人工智能AI技术,把图片中的人脸、车牌号码进行脱敏处理。该模型更多信息请访问项目', - limitFilesUpload:'只能上传 jpg/jpeg/png 格式的文件', - limitSizeUpload:'上传文件大小不能超过 20M !', modelManage: { modelManage: '模型管理', modelName: '模型名称', @@ -254,6 +283,8 @@ const zh = { deleteModelFileConfirmTips: '请确认是否删除当前模型文件?', modelFileDeleteFailed: '模型文件删除失败', }, -} +}; + + export default zh; diff --git a/web_src/vuepages/pages/notebook/debug/index.vue b/web_src/vuepages/pages/notebook/debug/index.vue new file mode 100644 index 000000000..77b2a7603 --- /dev/null +++ b/web_src/vuepages/pages/notebook/debug/index.vue @@ -0,0 +1,662 @@ + + + diff --git a/web_src/vuepages/pages/notebook/debug/vp-notebook-debug.js b/web_src/vuepages/pages/notebook/debug/vp-notebook-debug.js new file mode 100644 index 000000000..522b40992 --- /dev/null +++ b/web_src/vuepages/pages/notebook/debug/vp-notebook-debug.js @@ -0,0 +1,12 @@ +import Vue from 'vue'; +import {Dialog,Loading} from 'element-ui'; +import 'element-ui/lib/theme-chalk/index.css'; +import { i18n, lang } from '~/langs'; +import App from './index.vue'; + +Vue.use(Dialog) +Vue.use(Loading.directive) +new Vue({ + i18n, + render: (h) => h(App), +}).$mount('#__vue-root');