| @@ -55,6 +55,7 @@ coverage.all | |||
| !/custom/conf/templates | |||
| /custom/conf/app.ini | |||
| !/custom/conf/app.ini.sample | |||
| /custom/public/kanban | |||
| /data | |||
| /indexers | |||
| /log | |||
| @@ -206,7 +206,16 @@ func (task *Cloudbrain) CorrectCreateUnix() { | |||
| func (task *Cloudbrain) IsTerminal() bool { | |||
| status := task.Status | |||
| return status == string(ModelArtsTrainJobCompleted) || status == string(ModelArtsTrainJobFailed) || status == string(ModelArtsTrainJobKilled) || status == string(ModelArtsStopped) || status == string(JobStopped) || status == string(JobFailed) || status == string(JobSucceeded) | |||
| return status == string(ModelArtsTrainJobCompleted) || status == string(ModelArtsTrainJobFailed) || | |||
| status == string(ModelArtsTrainJobKilled) || status == string(ModelArtsStopped) || | |||
| status == string(JobStopped) || status == string(JobFailed) || | |||
| status == string(JobSucceeded) || status == GrampusStatusFailed || | |||
| status == GrampusStatusSucceeded || status == GrampusStatusStopped | |||
| } | |||
| func (task *Cloudbrain) IsRunning() bool { | |||
| status := task.Status | |||
| return status == string(ModelArtsTrainJobRunning) || status == string(ModelArtsRunning) || | |||
| status == string(JobRunning) || status == GrampusStatusRunning | |||
| } | |||
| func ConvertDurationToStr(duration int64) string { | |||
| @@ -920,7 +920,7 @@ func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time, | |||
| CountDate = time.Date(startTime.Year(), startTime.Month(), startTime.Day(), 0, 1, 0, 0, currentTimeNow.Location()) | |||
| } | |||
| DataDate := startTime.Format("2006-01-02") | |||
| DataDate := CountDate.Format("2006-01-02") | |||
| CodeMergeCountMap := queryPullRequest(start_unix, end_unix) | |||
| CommitCountMap := queryCommitAction(start_unix, end_unix, 5) | |||
| IssueCountMap := queryCreateIssue(start_unix, end_unix) | |||
| @@ -1103,6 +1103,7 @@ func updateNewUserAcitivity(currentUserActivity map[int64]map[int64]int64, userA | |||
| ",activate_regist_user=" + fmt.Sprint(useMetrics.ActivateRegistUser) + | |||
| ",not_activate_regist_user=" + fmt.Sprint(useMetrics.CurrentDayRegistUser-useMetrics.ActivateRegistUser) + | |||
| ",current_day_regist_user=" + fmt.Sprint(useMetrics.CurrentDayRegistUser) + | |||
| ",data_date='" + time.Unix(key, 0).Format("2006-01-02") + "'" + | |||
| " where count_date=" + fmt.Sprint(key) | |||
| statictisSess.Exec(updateSql) | |||
| @@ -19,6 +19,7 @@ const ( | |||
| ACCESS_TOKEN_PATH = "/cgi-bin/token" | |||
| QR_CODE_PATH = "/cgi-bin/qrcode/create" | |||
| GET_MATERIAL_PATH = "/cgi-bin/material/batchget_material" | |||
| SEND_TEMPLATE_PATH = "/cgi-bin/message/template/send" | |||
| ACTION_QR_STR_SCENE = "QR_STR_SCENE" | |||
| ERR_CODE_ACCESSTOKEN_EXPIRE = 42001 | |||
| @@ -41,12 +42,33 @@ type QRCodeRequest struct { | |||
| Action_info ActionInfo `json:"action_info"` | |||
| Expire_seconds int `json:"expire_seconds"` | |||
| } | |||
| type MaterialRequest struct { | |||
| Type string `json:"type"` | |||
| Offset int `json:"offset"` | |||
| Count int `json:"count"` | |||
| } | |||
| type TemplateMsgRequest struct { | |||
| ToUser string `json:"touser"` | |||
| TemplateId string `json:"template_id"` | |||
| Url string `json:"url"` | |||
| ClientMsgId string `json:"client_msg_id"` | |||
| Data interface{} `json:"data"` | |||
| } | |||
| type TemplateValue struct { | |||
| Value string `json:"value"` | |||
| Color string `json:"color"` | |||
| } | |||
| type CloudbrainTaskData struct { | |||
| First TemplateValue `json:"first"` | |||
| Keyword1 TemplateValue `json:"keyword1"` | |||
| Keyword2 TemplateValue `json:"keyword2"` | |||
| Keyword3 TemplateValue `json:"keyword3"` | |||
| Remark TemplateValue `json:"remark"` | |||
| } | |||
| type ActionInfo struct { | |||
| Scene Scene `json:"scene"` | |||
| } | |||
| @@ -161,3 +183,27 @@ func getErrorCodeFromResponse(r *resty.Response) int { | |||
| c, _ := strconv.Atoi(fmt.Sprint(code)) | |||
| return c | |||
| } | |||
| func sendTemplateMsg(req TemplateMsgRequest) (error, bool) { | |||
| client := getWechatRestyClient() | |||
| bodyJson, _ := json.Marshal(req) | |||
| r, err := client.R(). | |||
| SetHeader("Content-Type", "application/json"). | |||
| SetQueryParam("access_token", GetWechatAccessToken()). | |||
| SetBody(bodyJson). | |||
| Post(setting.WechatApiHost + SEND_TEMPLATE_PATH) | |||
| if err != nil { | |||
| log.Error("sendTemplateMsg,e=%v", err) | |||
| return nil, false | |||
| } | |||
| a := r.Body() | |||
| resultMap := make(map[string]interface{}, 0) | |||
| json.Unmarshal(a, &resultMap) | |||
| errcode := resultMap["errcode"] | |||
| log.Info("sendTemplateMsg,%v", r) | |||
| if errcode == fmt.Sprint(ERR_CODE_ACCESSTOKEN_EXPIRE) || errcode == fmt.Sprint(ERR_CODE_ACCESSTOKEN_INVALID) { | |||
| return nil, true | |||
| } | |||
| return nil, false | |||
| } | |||
| @@ -0,0 +1,145 @@ | |||
| package wechat | |||
| import ( | |||
| "code.gitea.io/gitea/models" | |||
| "code.gitea.io/gitea/modules/log" | |||
| "code.gitea.io/gitea/modules/setting" | |||
| "errors" | |||
| "fmt" | |||
| "time" | |||
| ) | |||
| type JobOperateType string | |||
| const ( | |||
| JobOperateTypeStart JobOperateType = "start" | |||
| JobOperateTypeStop JobOperateType = "stop" | |||
| ) | |||
| func GetJobOperateTypeFromCloudbrainStatus(cloudbrain *models.Cloudbrain) JobOperateType { | |||
| if cloudbrain.IsTerminal() { | |||
| return JobOperateTypeStop | |||
| } | |||
| if cloudbrain.IsRunning() { | |||
| return JobOperateTypeStart | |||
| } | |||
| return "" | |||
| } | |||
| func SendCloudbrainStartedMsg(operateType JobOperateType, cloudbrain models.Cloudbrain) error { | |||
| defer func() { | |||
| if err := recover(); err != nil { | |||
| combinedErr := fmt.Errorf("%s\n%s", err, log.Stack(2)) | |||
| log.Error("PANIC:", combinedErr) | |||
| } | |||
| }() | |||
| repo, err := models.GetRepositoryByID(cloudbrain.RepoID) | |||
| if err != nil { | |||
| log.Error("SendCloudbrainStartedMsg GetRepositoryByID error,%v", err) | |||
| } | |||
| if setting.CloudbrainStartedTemplateId == "" { | |||
| return nil | |||
| } | |||
| openId := models.GetUserWechatOpenId(cloudbrain.UserID) | |||
| if openId == "" { | |||
| return errors.New("Wechat openId not exist") | |||
| } | |||
| data := CloudbrainTaskData{ | |||
| First: TemplateValue{Value: getCloudbrainTemplateTitle(operateType)}, | |||
| Keyword1: TemplateValue{Value: cloudbrain.DisplayJobName}, | |||
| Keyword2: TemplateValue{Value: getJobTypeDisplayName(cloudbrain.JobType)}, | |||
| Keyword3: TemplateValue{Value: time.Unix(int64(cloudbrain.CreatedUnix), 0).Format("2006-01-02 15:04:05")}, | |||
| Remark: TemplateValue{Value: getCloudbrainTemplateRemark(operateType)}, | |||
| } | |||
| req := TemplateMsgRequest{ | |||
| ToUser: openId, | |||
| TemplateId: setting.CloudbrainStartedTemplateId, | |||
| Url: getCloudbrainTemplateUrl(cloudbrain, repo), | |||
| ClientMsgId: string(operateType) + "_" + fmt.Sprint(cloudbrain.ID), | |||
| Data: data, | |||
| } | |||
| err, retryFlag := sendTemplateMsg(req) | |||
| if retryFlag { | |||
| log.Info("retrySendCloudbrainTemplateMsg calling") | |||
| refreshAccessToken() | |||
| err, _ = sendTemplateMsg(req) | |||
| if err != nil { | |||
| log.Error("SendCloudbrainStartedMsg err. %v", err) | |||
| return err | |||
| } | |||
| return nil | |||
| } | |||
| if err != nil { | |||
| log.Error("SendCloudbrainStartedMsg err. %v", err) | |||
| return err | |||
| } | |||
| return nil | |||
| } | |||
| func getCloudbrainTemplateUrl(cloudbrain models.Cloudbrain, repo *models.Repository) string { | |||
| url := setting.AppURL + repo.FullName() | |||
| switch cloudbrain.JobType { | |||
| case string(models.JobTypeDebug): | |||
| if cloudbrain.ComputeResource == "CPU/GPU" { | |||
| url += "/cloudbrain/" + fmt.Sprint(cloudbrain.ID) | |||
| } else { | |||
| url += "/modelarts/notebook/" + fmt.Sprint(cloudbrain.ID) | |||
| } | |||
| case string(models.JobTypeBenchmark): | |||
| url += "/cloudbrain/benchmark/" + fmt.Sprint(cloudbrain.ID) | |||
| case string(models.JobTypeTrain): | |||
| if cloudbrain.Type == models.TypeCloudBrainOne { | |||
| url += "/cloudbrain/train-job/" + fmt.Sprint(cloudbrain.JobID) | |||
| } else if cloudbrain.Type == models.TypeCloudBrainTwo { | |||
| url += "/modelarts/train-job/" + fmt.Sprint(cloudbrain.JobID) | |||
| } else if cloudbrain.Type == models.TypeC2Net { | |||
| url += "/grampus/train-job/" + fmt.Sprint(cloudbrain.JobID) | |||
| } | |||
| case string(models.JobTypeInference): | |||
| url += "/modelarts/inference-job/" + fmt.Sprint(cloudbrain.JobID) | |||
| } | |||
| return url | |||
| } | |||
| func getCloudbrainTemplateTitle(operateType JobOperateType) string { | |||
| var title string | |||
| switch operateType { | |||
| case JobOperateTypeStart: | |||
| title = "您好,您提交的算力资源申请已通过,任务已启动,请您关注运行情况。" | |||
| case JobOperateTypeStop: | |||
| title = "您好,您提交的任务已运行结束。" | |||
| } | |||
| return title | |||
| } | |||
| func getCloudbrainTemplateRemark(operateType JobOperateType) string { | |||
| var remark string | |||
| switch operateType { | |||
| case JobOperateTypeStart: | |||
| remark = "感谢您的耐心等待。" | |||
| case JobOperateTypeStop: | |||
| remark = "点击可查看运行结果" | |||
| } | |||
| return remark | |||
| } | |||
| func getJobTypeDisplayName(jobType string) string { | |||
| switch jobType { | |||
| case string(models.JobTypeDebug): | |||
| return "调试任务" | |||
| case string(models.JobTypeBenchmark): | |||
| return "评测任务" | |||
| case string(models.JobTypeTrain): | |||
| return "训练任务" | |||
| case string(models.JobTypeInference): | |||
| return "推理任务" | |||
| } | |||
| return "" | |||
| } | |||
| @@ -56,4 +56,6 @@ type Notifier interface { | |||
| NotifySyncDeleteRef(doer *models.User, repo *models.Repository, refType, refFullName string) | |||
| NotifyOtherTask(doer *models.User, repo *models.Repository, id string, name string, optype models.ActionType) | |||
| NotifyChangeCloudbrainStatus(cloudbrain *models.Cloudbrain, oldStatus string) | |||
| } | |||
| @@ -158,3 +158,7 @@ func (*NullNotifier) NotifySyncDeleteRef(doer *models.User, repo *models.Reposit | |||
| func (*NullNotifier) NotifyOtherTask(doer *models.User, repo *models.Repository, id string, name string, optype models.ActionType) { | |||
| } | |||
| func (*NullNotifier) NotifyChangeCloudbrainStatus(cloudbrain *models.Cloudbrain, oldStatus string) { | |||
| } | |||
| @@ -12,6 +12,7 @@ import ( | |||
| "code.gitea.io/gitea/modules/notification/mail" | |||
| "code.gitea.io/gitea/modules/notification/ui" | |||
| "code.gitea.io/gitea/modules/notification/webhook" | |||
| wechatNotifier "code.gitea.io/gitea/modules/notification/wechat" | |||
| "code.gitea.io/gitea/modules/repository" | |||
| "code.gitea.io/gitea/modules/setting" | |||
| ) | |||
| @@ -35,6 +36,7 @@ func NewContext() { | |||
| RegisterNotifier(indexer.NewNotifier()) | |||
| RegisterNotifier(webhook.NewNotifier()) | |||
| RegisterNotifier(action.NewNotifier()) | |||
| RegisterNotifier(wechatNotifier.NewNotifier()) | |||
| } | |||
| // NotifyUploadAttachment notifies attachment upload message to notifiers | |||
| @@ -269,3 +271,10 @@ func NotifySyncDeleteRef(pusher *models.User, repo *models.Repository, refType, | |||
| notifier.NotifySyncDeleteRef(pusher, repo, refType, refFullName) | |||
| } | |||
| } | |||
| // NotifyChangeCloudbrainStatus | |||
| func NotifyChangeCloudbrainStatus(cloudbrain *models.Cloudbrain, oldStatus string) { | |||
| for _, notifier := range notifiers { | |||
| notifier.NotifyChangeCloudbrainStatus(cloudbrain, oldStatus) | |||
| } | |||
| } | |||
| @@ -0,0 +1,44 @@ | |||
| // Copyright 2019 The Gitea Authors. All rights reserved. | |||
| // Use of this source code is governed by a MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package wechat | |||
| import ( | |||
| "code.gitea.io/gitea/models" | |||
| "code.gitea.io/gitea/modules/auth/wechat" | |||
| "code.gitea.io/gitea/modules/notification/base" | |||
| "code.gitea.io/gitea/modules/setting" | |||
| ) | |||
| type wechatNotifier struct { | |||
| base.NullNotifier | |||
| } | |||
| var ( | |||
| _ base.Notifier = &wechatNotifier{} | |||
| ) | |||
| // NewNotifier create a new wechatNotifier notifier | |||
| func NewNotifier() base.Notifier { | |||
| return &wechatNotifier{} | |||
| } | |||
| func (*wechatNotifier) NotifyChangeCloudbrainStatus(cloudbrain *models.Cloudbrain, oldStatus string) { | |||
| operateType := wechat.GetJobOperateTypeFromCloudbrainStatus(cloudbrain) | |||
| if operateType == "" { | |||
| return | |||
| } | |||
| switch operateType { | |||
| case wechat.JobOperateTypeStart: | |||
| if len(setting.CloudbrainStartedNotifyList) == 0 { | |||
| return | |||
| } | |||
| for _, v := range setting.CloudbrainStartedNotifyList { | |||
| if v == cloudbrain.JobType { | |||
| go wechat.SendCloudbrainStartedMsg(operateType, *cloudbrain) | |||
| return | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -582,6 +582,10 @@ var ( | |||
| TreePathOfAutoMsgReply string | |||
| TreePathOfSubscribe string | |||
| //wechat template msg config | |||
| CloudbrainStartedTemplateId string | |||
| CloudbrainStartedNotifyList []string | |||
| //nginx proxy | |||
| PROXYURL string | |||
| RadarMap = struct { | |||
| @@ -1432,7 +1436,7 @@ func NewContext() { | |||
| WechatApiHost = sec.Key("HOST").MustString("https://api.weixin.qq.com") | |||
| WechatApiTimeoutSeconds = sec.Key("TIMEOUT_SECONDS").MustInt(3) | |||
| WechatAppId = sec.Key("APP_ID").MustString("wxba77b915a305a57d") | |||
| WechatAppSecret = sec.Key("APP_SECRET").MustString("e48e13f315adc32749ddc7057585f198") | |||
| WechatAppSecret = sec.Key("APP_SECRET").MustString("") | |||
| WechatQRCodeExpireSeconds = sec.Key("QR_CODE_EXPIRE_SECONDS").MustInt(120) | |||
| WechatAuthSwitch = sec.Key("AUTH_SWITCH").MustBool(true) | |||
| UserNameOfWechatReply = sec.Key("AUTO_REPLY_USER_NAME").MustString("OpenIOSSG") | |||
| @@ -1440,6 +1444,8 @@ func NewContext() { | |||
| RefNameOfWechatReply = sec.Key("AUTO_REPLY_REF_NAME").MustString("master") | |||
| TreePathOfAutoMsgReply = sec.Key("AUTO_REPLY_TREE_PATH").MustString("wechat/auto_reply.json") | |||
| TreePathOfSubscribe = sec.Key("SUBSCRIBE_TREE_PATH").MustString("wechat/subscribe_reply.json") | |||
| CloudbrainStartedTemplateId = sec.Key("CLOUDBRAIN_STARTED_TEMPLATE_ID").MustString("") | |||
| CloudbrainStartedNotifyList = strings.Split(sec.Key("CLOUDBRAIN_STARTED_NOTIFY_LIST").MustString("DEBUG"), ",") | |||
| SetRadarMapConfig() | |||
| @@ -187,9 +187,6 @@ func GetOneLevelAllObjectUnderDirMinio(bucket string, prefixRootPath string, rel | |||
| if val.Key == Prefix { | |||
| continue | |||
| } | |||
| if strings.Contains(val.Key[prefixLen:len(val.Key)-1], "/") { | |||
| continue | |||
| } | |||
| if strings.HasSuffix(val.Key, "/") { | |||
| isDir = true | |||
| fileName = val.Key[prefixLen : len(val.Key)-1] | |||
| @@ -1007,7 +1007,7 @@ cloudbrain.time.starttime=Start run time | |||
| cloudbrain.time.endtime=End run time | |||
| cloudbrain.datasetdownload=Dataset download url | |||
| model_manager = Model | |||
| model_noright=No right | |||
| model_noright=You have no right to do the operation. | |||
| model_rename=Duplicate model name, please modify model name. | |||
| date=Date | |||
| @@ -1225,7 +1225,7 @@ model.manage.create_new_convert_task=Create Model Transformation Task | |||
| modelconvert.manage.create_error1=A model transformation task with the same name already exists. | |||
| modelconvert.manage.create_error2=Only one running model transformation task can be created. | |||
| modelconvert.manage.model_not_exist=The model does not exist. | |||
| modelconvert.manage.no_operate_right=No operation permission. | |||
| modelconvert.manage.no_operate_right=You have no right to do the operation. | |||
| grampus.train_job.ai_center = AI Center | |||
| grampus.dataset_path_rule = The code is storaged in /cache/code;the dataset is storaged in /cache/dataset;and please put your model into /cache/output, then you can download it online。 | |||
| @@ -1006,7 +1006,7 @@ datasets.desc=数据集功能 | |||
| cloudbrain_helper=使用GPU/NPU资源,开启Notebook、模型训练任务等 | |||
| model_manager = 模型 | |||
| model_noright=无权限操作 | |||
| model_noright=您没有操作权限。 | |||
| model_rename=模型名称重复,请修改模型名称 | |||
| @@ -1237,7 +1237,7 @@ model.manage.create_new_convert_task=创建模型转换任务 | |||
| modelconvert.manage.create_error1=相同的名称模型转换任务已经存在。 | |||
| modelconvert.manage.create_error2=只能创建一个正在运行的模型转换任务。 | |||
| modelconvert.manage.model_not_exist=选择的模型不存在。 | |||
| modelconvert.manage.no_operate_right=无操作权限。 | |||
| modelconvert.manage.no_operate_right=您没有操作权限。 | |||
| grampus.train_job.ai_center=智算中心 | |||
| grampus.dataset_path_rule = 训练脚本存储在/cache/code中,数据集存储在/cache/dataset中,训练输出请存储在/cache/output中以供后续下载。 | |||
| @@ -6,6 +6,7 @@ | |||
| package repo | |||
| import ( | |||
| "code.gitea.io/gitea/modules/notification" | |||
| "encoding/json" | |||
| "net/http" | |||
| "sort" | |||
| @@ -74,7 +75,7 @@ func GetCloudbrainTask(ctx *context.APIContext) { | |||
| log.Error("ConvertToJobResultPayload failed:", err) | |||
| return | |||
| } | |||
| oldStatus := job.Status | |||
| job.Status = result.JobStatus.State | |||
| taskRoles := result.TaskRoles | |||
| taskRes, _ := models.ConvertToTaskPod(taskRoles[cloudbrain.SubTaskName].(map[string]interface{})) | |||
| @@ -86,6 +87,9 @@ func GetCloudbrainTask(ctx *context.APIContext) { | |||
| if result.JobStatus.State != string(models.JobWaiting) { | |||
| models.ParseAndSetDurationFromCloudBrainOne(result, job) | |||
| if oldStatus != job.Status { | |||
| notification.NotifyChangeCloudbrainStatus(job, oldStatus) | |||
| } | |||
| err = models.UpdateJob(job) | |||
| if err != nil { | |||
| log.Error("UpdateJob failed:", err) | |||
| @@ -124,7 +128,7 @@ func GetCloudBrainInferenceJob(ctx *context.APIContext) { | |||
| log.Error("ConvertToJobResultPayload failed:", err) | |||
| return | |||
| } | |||
| oldStatus := job.Status | |||
| job.Status = result.JobStatus.State | |||
| if result.JobStatus.State != string(models.JobWaiting) && result.JobStatus.State != string(models.JobFailed) { | |||
| taskRoles := result.TaskRoles | |||
| @@ -137,6 +141,9 @@ func GetCloudBrainInferenceJob(ctx *context.APIContext) { | |||
| if result.JobStatus.State != string(models.JobWaiting) { | |||
| models.ParseAndSetDurationFromCloudBrainOne(result, job) | |||
| if oldStatus != job.Status { | |||
| notification.NotifyChangeCloudbrainStatus(job, oldStatus) | |||
| } | |||
| err = models.UpdateJob(job) | |||
| if err != nil { | |||
| log.Error("UpdateJob failed:", err) | |||
| @@ -6,6 +6,7 @@ | |||
| package repo | |||
| import ( | |||
| "code.gitea.io/gitea/modules/notification" | |||
| "encoding/json" | |||
| "net/http" | |||
| "path" | |||
| @@ -42,8 +43,11 @@ func GetModelArtsNotebook(ctx *context.APIContext) { | |||
| ctx.NotFound(err) | |||
| return | |||
| } | |||
| oldStatus := job.Status | |||
| job.Status = result.Status | |||
| if oldStatus != result.Status { | |||
| notification.NotifyChangeCloudbrainStatus(job, oldStatus) | |||
| } | |||
| err = models.UpdateJob(job) | |||
| if err != nil { | |||
| log.Error("UpdateJob failed:", err) | |||
| @@ -75,12 +79,16 @@ func GetModelArtsNotebook2(ctx *context.APIContext) { | |||
| if job.StartTime == 0 && result.Lease.UpdateTime > 0 { | |||
| job.StartTime = timeutil.TimeStamp(result.Lease.UpdateTime / 1000) | |||
| } | |||
| oldStatus := job.Status | |||
| job.Status = result.Status | |||
| if job.EndTime == 0 && models.IsModelArtsDebugJobTerminal(job.Status) { | |||
| job.EndTime = timeutil.TimeStampNow() | |||
| } | |||
| job.CorrectCreateUnix() | |||
| job.ComputeAndSetDuration() | |||
| if oldStatus != result.Status { | |||
| notification.NotifyChangeCloudbrainStatus(job, oldStatus) | |||
| } | |||
| err = models.UpdateJob(job) | |||
| if err != nil { | |||
| log.Error("UpdateJob failed:", err) | |||
| @@ -112,10 +120,13 @@ func GetModelArtsTrainJob(ctx *context.APIContext) { | |||
| ctx.NotFound(err) | |||
| return | |||
| } | |||
| oldStatus := job.Status | |||
| job.Status = modelarts.TransTrainJobStatus(result.IntStatus) | |||
| job.Duration = result.Duration | |||
| job.TrainJobDuration = result.TrainJobDuration | |||
| if oldStatus != job.Status { | |||
| notification.NotifyChangeCloudbrainStatus(job, oldStatus) | |||
| } | |||
| err = models.UpdateJob(job) | |||
| if err != nil { | |||
| log.Error("UpdateJob failed:", err) | |||
| @@ -156,7 +167,7 @@ func GetModelArtsTrainJobVersion(ctx *context.APIContext) { | |||
| log.Error("ConvertToJobResultPayload failed:", err) | |||
| return | |||
| } | |||
| oldStatus := job.Status | |||
| job.Status = result.JobStatus.State | |||
| if result.JobStatus.State != string(models.JobWaiting) && result.JobStatus.State != string(models.JobFailed) { | |||
| taskRoles := result.TaskRoles | |||
| @@ -169,6 +180,9 @@ func GetModelArtsTrainJobVersion(ctx *context.APIContext) { | |||
| if result.JobStatus.State != string(models.JobWaiting) { | |||
| models.ParseAndSetDurationFromCloudBrainOne(result, job) | |||
| if oldStatus != job.Status { | |||
| notification.NotifyChangeCloudbrainStatus(job, oldStatus) | |||
| } | |||
| err = models.UpdateJob(job) | |||
| if err != nil { | |||
| log.Error("UpdateJob failed:", err) | |||
| @@ -152,6 +152,10 @@ func saveModelByParameters(jobId string, versionName string, name string, versio | |||
| } | |||
| func SaveNewNameModel(ctx *context.Context) { | |||
| if !ctx.Repo.CanWrite(models.UnitTypeModelManage) { | |||
| ctx.Error(403, ctx.Tr("repo.model_noright")) | |||
| return | |||
| } | |||
| name := ctx.Query("Name") | |||
| if name == "" { | |||
| ctx.Error(500, fmt.Sprintf("name or version is null.")) | |||
| @@ -169,6 +173,10 @@ func SaveNewNameModel(ctx *context.Context) { | |||
| } | |||
| func SaveModel(ctx *context.Context) { | |||
| if !ctx.Repo.CanWrite(models.UnitTypeModelManage) { | |||
| ctx.Error(403, ctx.Tr("repo.model_noright")) | |||
| return | |||
| } | |||
| log.Info("save model start.") | |||
| JobId := ctx.Query("JobId") | |||
| VersionName := ctx.Query("VersionName") | |||
| @@ -177,16 +185,8 @@ func SaveModel(ctx *context.Context) { | |||
| label := ctx.Query("Label") | |||
| description := ctx.Query("Description") | |||
| engine := ctx.QueryInt("Engine") | |||
| trainTaskCreate := ctx.QueryBool("trainTaskCreate") | |||
| modelSelectedFile := ctx.Query("modelSelectedFile") | |||
| log.Info("engine=" + fmt.Sprint(engine) + " modelSelectedFile=" + modelSelectedFile) | |||
| if !trainTaskCreate { | |||
| if !ctx.Repo.CanWrite(models.UnitTypeModelManage) { | |||
| //ctx.NotFound(ctx.Req.URL.RequestURI(), nil) | |||
| ctx.JSON(403, ctx.Tr("repo.model_noright")) | |||
| return | |||
| } | |||
| } | |||
| if JobId == "" || VersionName == "" { | |||
| ctx.Error(500, fmt.Sprintf("JobId or VersionName is null.")) | |||
| @@ -2,6 +2,7 @@ package repo | |||
| import ( | |||
| "bufio" | |||
| "code.gitea.io/gitea/modules/notification" | |||
| "encoding/json" | |||
| "errors" | |||
| "fmt" | |||
| @@ -886,6 +887,7 @@ func CloudBrainTrainJobShow(ctx *context.Context) { | |||
| func cloudBrainShow(ctx *context.Context, tpName base.TplName, jobType models.JobType) { | |||
| ctx.Data["PageIsCloudBrain"] = true | |||
| debugListType := ctx.Query("debugListType") | |||
| cloudbrain.InitSpecialPool() | |||
| var task *models.Cloudbrain | |||
| var err error | |||
| @@ -897,22 +899,22 @@ func cloudBrainShow(ctx *context.Context, tpName base.TplName, jobType models.Jo | |||
| if err != nil { | |||
| log.Info("error:" + err.Error()) | |||
| ctx.Data["error"] = err.Error() | |||
| ctx.NotFound(ctx.Req.URL.RequestURI(), nil) | |||
| return | |||
| } | |||
| result, err := cloudbrain.GetJob(task.JobID) | |||
| if err != nil { | |||
| log.Info("error:" + err.Error()) | |||
| ctx.Data["error"] = err.Error() | |||
| ctx.NotFound(ctx.Req.URL.RequestURI(), nil) | |||
| return | |||
| } | |||
| hasSpec := false | |||
| if task.JobType == string(models.JobTypeTrain) { | |||
| if cloudbrain.TrainResourceSpecs == nil { | |||
| json.Unmarshal([]byte(setting.TrainResourceSpecs), &cloudbrain.TrainResourceSpecs) | |||
| } | |||
| hasSpec := false | |||
| for _, tmp := range cloudbrain.TrainResourceSpecs.ResourceSpec { | |||
| if tmp.Id == task.ResourceSpecId { | |||
| hasSpec = true | |||
| @@ -920,24 +922,7 @@ func cloudBrainShow(ctx *context.Context, tpName base.TplName, jobType models.Jo | |||
| ctx.Data["CpuNum"] = tmp.CpuNum | |||
| ctx.Data["MemMiB"] = tmp.MemMiB | |||
| ctx.Data["ShareMemMiB"] = tmp.ShareMemMiB | |||
| } | |||
| } | |||
| if !hasSpec && cloudbrain.SpecialPools != nil { | |||
| for _, specialPool := range cloudbrain.SpecialPools.Pools { | |||
| if specialPool.ResourceSpec != nil { | |||
| for _, spec := range specialPool.ResourceSpec { | |||
| if task.ResourceSpecId == spec.Id { | |||
| ctx.Data["GpuNum"] = spec.GpuNum | |||
| ctx.Data["CpuNum"] = spec.CpuNum | |||
| ctx.Data["MemMiB"] = spec.MemMiB | |||
| ctx.Data["ShareMemMiB"] = spec.ShareMemMiB | |||
| break | |||
| } | |||
| } | |||
| } | |||
| break | |||
| } | |||
| } | |||
| @@ -947,10 +932,12 @@ func cloudBrainShow(ctx *context.Context, tpName base.TplName, jobType models.Jo | |||
| } | |||
| for _, tmp := range cloudbrain.InferenceResourceSpecs.ResourceSpec { | |||
| if tmp.Id == task.ResourceSpecId { | |||
| hasSpec = true | |||
| ctx.Data["GpuNum"] = tmp.GpuNum | |||
| ctx.Data["CpuNum"] = tmp.CpuNum | |||
| ctx.Data["MemMiB"] = tmp.MemMiB | |||
| ctx.Data["ShareMemMiB"] = tmp.ShareMemMiB | |||
| break | |||
| } | |||
| } | |||
| } else { | |||
| @@ -959,10 +946,32 @@ func cloudBrainShow(ctx *context.Context, tpName base.TplName, jobType models.Jo | |||
| } | |||
| for _, tmp := range cloudbrain.ResourceSpecs.ResourceSpec { | |||
| if tmp.Id == task.ResourceSpecId { | |||
| hasSpec = true | |||
| ctx.Data["GpuNum"] = tmp.GpuNum | |||
| ctx.Data["CpuNum"] = tmp.CpuNum | |||
| ctx.Data["MemMiB"] = tmp.MemMiB | |||
| ctx.Data["ShareMemMiB"] = tmp.ShareMemMiB | |||
| break | |||
| } | |||
| } | |||
| } | |||
| if !hasSpec && cloudbrain.SpecialPools != nil { | |||
| for _, specialPool := range cloudbrain.SpecialPools.Pools { | |||
| if specialPool.ResourceSpec != nil { | |||
| for _, spec := range specialPool.ResourceSpec { | |||
| if task.ResourceSpecId == spec.Id { | |||
| ctx.Data["GpuNum"] = spec.GpuNum | |||
| ctx.Data["CpuNum"] = spec.CpuNum | |||
| ctx.Data["MemMiB"] = spec.MemMiB | |||
| ctx.Data["ShareMemMiB"] = spec.ShareMemMiB | |||
| break | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -981,14 +990,6 @@ func cloudBrainShow(ctx *context.Context, tpName base.TplName, jobType models.Jo | |||
| ctx.Data["resource_type"] = resourceType.Value | |||
| } | |||
| } | |||
| for _, specialPool := range cloudbrain.SpecialPools.Pools { | |||
| for _, resourceType := range specialPool.Pool { | |||
| if resourceType.Queue == jobRes.Config.GpuType { | |||
| ctx.Data["resource_type"] = resourceType.Value | |||
| } | |||
| } | |||
| } | |||
| } else if task.JobType == string(models.JobTypeInference) { | |||
| if inferenceGpuInfos == nil { | |||
| @@ -1020,16 +1021,30 @@ func cloudBrainShow(ctx *context.Context, tpName base.TplName, jobType models.Jo | |||
| } | |||
| } | |||
| } | |||
| if cloudbrain.SpecialPools != nil { | |||
| for _, specialPool := range cloudbrain.SpecialPools.Pools { | |||
| for _, resourceType := range specialPool.Pool { | |||
| if resourceType.Queue == jobRes.Config.GpuType { | |||
| ctx.Data["resource_type"] = resourceType.Value | |||
| } | |||
| } | |||
| } | |||
| } | |||
| 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.ContainerID = taskRes.TaskStatuses[0].ContainerID | |||
| task.ContainerIp = taskRes.TaskStatuses[0].ContainerIP | |||
| 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() | |||
| @@ -1145,6 +1160,20 @@ func CloudBrainCommitImageShow(ctx *context.Context) { | |||
| ctx.HTML(200, tplCloudBrainImageSubmit) | |||
| } | |||
| func GetImage(ctx *context.Context) { | |||
| var ID = ctx.Params(":id") | |||
| id, _ := strconv.ParseInt(ID, 10, 64) | |||
| image, err := models.GetImageByID(id) | |||
| if err != nil { | |||
| log.Error("GetImageByID failed:%v", err.Error()) | |||
| ctx.JSON(http.StatusNotFound, nil) | |||
| } | |||
| ctx.JSON(http.StatusOK, image) | |||
| } | |||
| func CloudBrainImageEdit(ctx *context.Context) { | |||
| ctx.Data["PageIsImageEdit"] = true | |||
| ctx.Data["PageFrom"] = ctx.Params(":from") | |||
| @@ -1369,12 +1398,15 @@ func CloudBrainStop(ctx *context.Context) { | |||
| errorMsg = "cloudbrain.Stopped_failed" | |||
| break | |||
| } | |||
| oldStatus := task.Status | |||
| task.Status = string(models.JobStopped) | |||
| if task.EndTime == 0 { | |||
| task.EndTime = timeutil.TimeStampNow() | |||
| } | |||
| task.ComputeAndSetDuration() | |||
| if oldStatus != task.Status { | |||
| notification.NotifyChangeCloudbrainStatus(task, oldStatus) | |||
| } | |||
| err = models.UpdateJob(task) | |||
| if err != nil { | |||
| log.Error("UpdateJob(%s) failed:%v", task.JobName, err, ctx.Data["msgID"]) | |||
| @@ -1468,11 +1500,15 @@ func logErrorAndUpdateJobStatus(err error, taskInfo *models.Cloudbrain) { | |||
| if err != nil { | |||
| log.Warn("Failed to stop cloudBrain job:"+taskInfo.JobID, err) | |||
| } else { | |||
| oldStatus := taskInfo.Status | |||
| taskInfo.Status = string(models.JobStopped) | |||
| if taskInfo.EndTime == 0 { | |||
| taskInfo.EndTime = timeutil.TimeStampNow() | |||
| } | |||
| taskInfo.ComputeAndSetDuration() | |||
| if oldStatus != taskInfo.Status { | |||
| notification.NotifyChangeCloudbrainStatus(taskInfo, oldStatus) | |||
| } | |||
| err = models.UpdateJob(taskInfo) | |||
| if err != nil { | |||
| log.Warn("UpdateJob failed", err) | |||
| @@ -1952,9 +1988,13 @@ func SyncCloudbrainStatus() { | |||
| jobRes, _ := models.ConvertToJobResultPayload(result.Payload) | |||
| taskRoles := jobRes.TaskRoles | |||
| taskRes, _ := models.ConvertToTaskPod(taskRoles[cloudbrain.SubTaskName].(map[string]interface{})) | |||
| oldStatus := task.Status | |||
| task.Status = taskRes.TaskStatuses[0].State | |||
| if task.Status != string(models.JobWaiting) { | |||
| models.ParseAndSetDurationFromCloudBrainOne(jobRes, task) | |||
| if oldStatus != task.Status { | |||
| notification.NotifyChangeCloudbrainStatus(task, oldStatus) | |||
| } | |||
| err = models.UpdateJob(task) | |||
| if err != nil { | |||
| log.Error("UpdateJob(%s) failed:%v", task.JobName, err) | |||
| @@ -1981,6 +2021,9 @@ func SyncCloudbrainStatus() { | |||
| task.EndTime = timeutil.TimeStampNow() | |||
| } | |||
| task.ComputeAndSetDuration() | |||
| if oldStatus != task.Status { | |||
| notification.NotifyChangeCloudbrainStatus(task, oldStatus) | |||
| } | |||
| err = models.UpdateJob(task) | |||
| if err != nil { | |||
| log.Error("UpdateJob(%s) failed:%v", task.DisplayJobName, err) | |||
| @@ -1999,6 +2042,7 @@ func SyncCloudbrainStatus() { | |||
| } | |||
| 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) | |||
| @@ -2008,6 +2052,9 @@ func SyncCloudbrainStatus() { | |||
| } | |||
| task.CorrectCreateUnix() | |||
| task.ComputeAndSetDuration() | |||
| if oldStatus != task.Status { | |||
| notification.NotifyChangeCloudbrainStatus(task, oldStatus) | |||
| } | |||
| err = models.UpdateJob(task) | |||
| if err != nil { | |||
| log.Error("UpdateJob(%s) failed:%v", task.JobName, err) | |||
| @@ -2022,6 +2069,7 @@ func SyncCloudbrainStatus() { | |||
| } | |||
| if result != nil { | |||
| oldStatus := task.Status | |||
| task.Status = modelarts.TransTrainJobStatus(result.IntStatus) | |||
| task.Duration = result.Duration / 1000 | |||
| task.TrainJobDuration = result.TrainJobDuration | |||
| @@ -2034,6 +2082,9 @@ func SyncCloudbrainStatus() { | |||
| task.EndTime = task.StartTime.Add(task.Duration) | |||
| } | |||
| task.CorrectCreateUnix() | |||
| if oldStatus != task.Status { | |||
| notification.NotifyChangeCloudbrainStatus(task, oldStatus) | |||
| } | |||
| err = models.UpdateJob(task) | |||
| if err != nil { | |||
| log.Error("UpdateJob(%s) failed:%v", task.JobName, err) | |||
| @@ -2054,6 +2105,7 @@ func SyncCloudbrainStatus() { | |||
| if len(result.JobInfo.Tasks[0].CenterID) == 1 && len(result.JobInfo.Tasks[0].CenterName) == 1 { | |||
| task.AiCenter = result.JobInfo.Tasks[0].CenterID[0] + "+" + result.JobInfo.Tasks[0].CenterName[0] | |||
| } | |||
| oldStatus := task.Status | |||
| task.Status = grampus.TransTrainJobStatus(result.JobInfo.Status) | |||
| task.Duration = result.JobInfo.RunSec | |||
| task.TrainJobDuration = models.ConvertDurationToStr(task.Duration) | |||
| @@ -2065,6 +2117,9 @@ func SyncCloudbrainStatus() { | |||
| task.EndTime = task.StartTime.Add(task.Duration) | |||
| } | |||
| task.CorrectCreateUnix() | |||
| if oldStatus != task.Status { | |||
| notification.NotifyChangeCloudbrainStatus(task, oldStatus) | |||
| } | |||
| err = models.UpdateJob(task) | |||
| if err != nil { | |||
| log.Error("UpdateJob(%s) failed:%v", task.JobName, err) | |||
| @@ -1,6 +1,13 @@ | |||
| package repo | |||
| import ( | |||
| "code.gitea.io/gitea/modules/auth" | |||
| "code.gitea.io/gitea/modules/git" | |||
| "code.gitea.io/gitea/modules/grampus" | |||
| "code.gitea.io/gitea/modules/modelarts" | |||
| "code.gitea.io/gitea/modules/notification" | |||
| "code.gitea.io/gitea/modules/timeutil" | |||
| "code.gitea.io/gitea/modules/util" | |||
| "encoding/json" | |||
| "errors" | |||
| "io/ioutil" | |||
| @@ -638,12 +645,15 @@ func GrampusStopJob(ctx *context.Context) { | |||
| errorMsg = res.ErrorMsg | |||
| break | |||
| } | |||
| oldStatus := task.Status | |||
| task.Status = string(models.GrampusStatusStopped) | |||
| if task.EndTime == 0 { | |||
| task.EndTime = timeutil.TimeStampNow() | |||
| } | |||
| task.ComputeAndSetDuration() | |||
| if oldStatus != task.Status { | |||
| notification.NotifyChangeCloudbrainStatus(task, oldStatus) | |||
| } | |||
| err = models.UpdateJob(task) | |||
| if err != nil { | |||
| log.Error("UpdateJob(%s) failed:%v", task.JobName, err, ctx.Data["msgID"]) | |||
| @@ -714,7 +724,7 @@ func GrampusTrainJobShow(ctx *context.Context) { | |||
| task, err := models.GetCloudbrainByJobIDWithDeleted(ctx.Params(":jobid")) | |||
| if err != nil { | |||
| log.Error("GetCloudbrainByJobID failed:" + err.Error()) | |||
| ctx.ServerError("system error", err) | |||
| ctx.NotFound(ctx.Req.URL.RequestURI(), nil) | |||
| return | |||
| } | |||
| @@ -722,14 +732,15 @@ func GrampusTrainJobShow(ctx *context.Context) { | |||
| result, err := grampus.GetJob(task.JobID) | |||
| if err != nil { | |||
| log.Error("GetJob failed:" + err.Error()) | |||
| //ctx.ServerError("GetJob failed", err) | |||
| //return | |||
| ctx.NotFound(ctx.Req.URL.RequestURI(), nil) | |||
| return | |||
| } | |||
| if result != nil { | |||
| if len(result.JobInfo.Tasks[0].CenterID) == 1 && len(result.JobInfo.Tasks[0].CenterName) == 1 { | |||
| task.AiCenter = result.JobInfo.Tasks[0].CenterID[0] + "+" + result.JobInfo.Tasks[0].CenterName[0] | |||
| } | |||
| oldStatus := task.Status | |||
| task.Status = grampus.TransTrainJobStatus(result.JobInfo.Status) | |||
| if task.Status != result.JobInfo.Status || result.JobInfo.Status == models.GrampusStatusRunning { | |||
| task.Duration = result.JobInfo.RunSec | |||
| @@ -742,6 +753,9 @@ func GrampusTrainJobShow(ctx *context.Context) { | |||
| task.EndTime = task.StartTime.Add(task.Duration) | |||
| } | |||
| task.CorrectCreateUnix() | |||
| if oldStatus != task.Status { | |||
| notification.NotifyChangeCloudbrainStatus(task, oldStatus) | |||
| } | |||
| err = models.UpdateJob(task) | |||
| if err != nil { | |||
| log.Error("UpdateJob failed:" + err.Error()) | |||
| @@ -257,27 +257,29 @@ func NotebookShow(ctx *context.Context) { | |||
| var ID = ctx.Params(":id") | |||
| task, err := models.GetCloudbrainByIDWithDeleted(ID) | |||
| if err != nil { | |||
| ctx.Data["error"] = err.Error() | |||
| ctx.RenderWithErr(err.Error(), tplModelArtsNotebookShow, nil) | |||
| log.Error("GET job error", err.Error()) | |||
| ctx.NotFound(ctx.Req.URL.RequestURI(), nil) | |||
| return | |||
| } | |||
| result, err := modelarts.GetNotebook2(task.JobID) | |||
| if err != nil { | |||
| ctx.Data["error"] = err.Error() | |||
| ctx.RenderWithErr(err.Error(), tplModelArtsNotebookShow, nil) | |||
| log.Error("GET job error", err.Error()) | |||
| ctx.NotFound(ctx.Req.URL.RequestURI(), nil) | |||
| return | |||
| } | |||
| if result != nil { | |||
| if task.DeletedAt.IsZero() { //normal record | |||
| if task.Status != result.Status { | |||
| oldStatus := task.Status | |||
| task.Status = result.Status | |||
| models.ParseAndSetDurationFromModelArtsNotebook(result, task) | |||
| notification.NotifyChangeCloudbrainStatus(task, oldStatus) | |||
| err = models.UpdateJob(task) | |||
| if err != nil { | |||
| ctx.Data["error"] = err.Error() | |||
| ctx.RenderWithErr(err.Error(), tplModelArtsNotebookShow, nil) | |||
| log.Error("GET job error", err.Error()) | |||
| ctx.NotFound(ctx.Req.URL.RequestURI(), nil) | |||
| return | |||
| } | |||
| } | |||
| @@ -510,11 +512,15 @@ func NotebookManage(ctx *context.Context) { | |||
| ID = strconv.FormatInt(newTask.ID, 10) | |||
| notification.NotifyOtherTask(ctx.User, ctx.Repo.Repository, ID, task.DisplayJobName, models.ActionCreateDebugNPUTask) | |||
| } else { | |||
| oldStatus := task.Status | |||
| task.Status = res.Status | |||
| if task.EndTime == 0 && models.IsModelArtsDebugJobTerminal(task.Status) { | |||
| task.EndTime = timeutil.TimeStampNow() | |||
| } | |||
| task.ComputeAndSetDuration() | |||
| if oldStatus != task.Status { | |||
| notification.NotifyChangeCloudbrainStatus(task, oldStatus) | |||
| } | |||
| err = models.UpdateJob(task) | |||
| if err != nil { | |||
| log.Error("UpdateJob(%s) failed:%v", task.JobName, err.Error(), ctx.Data["MsgID"]) | |||
| @@ -1649,7 +1655,11 @@ func TrainJobShow(ctx *context.Context) { | |||
| if err != nil { | |||
| log.Error("GetVersionListTasks(%s) failed:%v", jobID, err.Error()) | |||
| ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobShow, nil) | |||
| ctx.NotFound(ctx.Req.URL.RequestURI(), nil) | |||
| return | |||
| } | |||
| if len(VersionListTasks) == 0 { | |||
| ctx.NotFound(ctx.Req.URL.RequestURI(), nil) | |||
| return | |||
| } | |||
| //设置权限 | |||
| @@ -2309,7 +2319,7 @@ func InferenceJobShow(ctx *context.Context) { | |||
| if err != nil { | |||
| log.Error("GetInferenceTask(%s) failed:%v", jobID, err.Error()) | |||
| ctx.RenderWithErr(err.Error(), tplModelArtsInferenceJobShow, nil) | |||
| ctx.NotFound(ctx.Req.URL.RequestURI(), nil) | |||
| return | |||
| } | |||
| //设置权限 | |||
| @@ -1016,6 +1016,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
| }, context.RepoAssignment(), context.RepoMustNotBeArchived(), reqRepoAdmin) | |||
| m.Group("/image/:id", func() { | |||
| m.Get("", repo.GetImage) | |||
| m.Get("/:from", cloudbrain.AdminOrImageCreaterRight, repo.CloudBrainImageEdit) | |||
| m.Post("", cloudbrain.AdminOrImageCreaterRight, bindIgnErr(auth.EditImageCloudBrainForm{}), repo.CloudBrainImageEditPost) | |||
| m.Delete("", cloudbrain.AdminOrImageCreaterRight, repo.CloudBrainImageDelete) | |||
| @@ -35,7 +35,7 @@ | |||
| {{range .Datasets}} | |||
| <tr> | |||
| <td>{{.ID}}</td> | |||
| <td style="display: flex;align-items: center;"><a href="{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Alias}}/datasets">{{.Title}}</a>{{if .Recommend}}<img src="/img/jian.svg" style="margin-left: 0.5rem;">{{end}}</td> | |||
| <td style="display: flex;align-items: center;"><a href="{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}/datasets">{{.Title}}</a>{{if .Recommend}}<img src="/img/jian.svg" style="margin-left: 0.5rem;">{{end}}</td> | |||
| <td><i class="fa fa{{if .IsPrivate}}-check{{end}}-square-o"></i></td> | |||
| <td><span title="{{.CreatedUnix.FormatLong}}">{{.CreatedUnix.FormatShort}}</span></td> | |||
| <td>{{if .Recommend}}<span class="set_dataset" style="color: rgb(250, 140, 22);cursor: pointer;" data-url="{{$.Link}}/{{.ID}}/action/unrecommend">{{$.i18n.Tr "admin.datasets.unrecommend"}}</span>{{else}}<span class="set_dataset" style="color: rgb(19, 194, 141);cursor: pointer;" data-url="{{$.Link}}/{{.ID}}/action/recommend">{{$.i18n.Tr "admin.datasets.recommend"}}</span>{{end}}</td> | |||
| @@ -48,4 +48,4 @@ | |||
| {{template "base/paginate" .}} | |||
| </div> | |||
| </div> | |||
| {{template "base/footer" .}} | |||
| {{template "base/footer" .}} | |||
| @@ -109,6 +109,11 @@ | |||
| ], | |||
| {{end}} | |||
| }; | |||
| {{if .IsSigned}} | |||
| window.sessionStorage.setItem('_csrf', '{{.CsrfToken}}'); | |||
| {{else}} | |||
| window.sessionStorage.removeItem('_csrf'); | |||
| {{end}} | |||
| </script> | |||
| <link rel="shortcut icon" href="{{StaticUrlPrefix}}/img/favicon.png"> | |||
| <link rel="mask-icon" href="{{StaticUrlPrefix}}/img/openi-safari.svg" color="#609926"> | |||
| @@ -109,6 +109,11 @@ | |||
| ], | |||
| {{end}} | |||
| }; | |||
| {{if .IsSigned}} | |||
| window.sessionStorage.setItem('_csrf', '{{.CsrfToken}}'); | |||
| {{else}} | |||
| window.sessionStorage.removeItem('_csrf'); | |||
| {{end}} | |||
| </script> | |||
| <link rel="shortcut icon" href="{{StaticUrlPrefix}}/img/favicon.png"> | |||
| <link rel="mask-icon" href="{{StaticUrlPrefix}}/img/openi-safari.svg" color="#609926"> | |||
| @@ -109,6 +109,11 @@ | |||
| ], | |||
| {{end}} | |||
| }; | |||
| {{if .IsSigned}} | |||
| window.sessionStorage.setItem('_csrf', '{{.CsrfToken}}'); | |||
| {{else}} | |||
| window.sessionStorage.removeItem('_csrf'); | |||
| {{end}} | |||
| </script> | |||
| <link rel="shortcut icon" href="{{StaticUrlPrefix}}/img/favicon.png"> | |||
| <link rel="mask-icon" href="{{StaticUrlPrefix}}/img/openi-safari.svg" color="#609926"> | |||
| @@ -109,6 +109,11 @@ | |||
| ], | |||
| {{end}} | |||
| }; | |||
| {{if .IsSigned}} | |||
| window.sessionStorage.setItem('_csrf', '{{.CsrfToken}}'); | |||
| {{else}} | |||
| window.sessionStorage.removeItem('_csrf'); | |||
| {{end}} | |||
| </script> | |||
| <link rel="shortcut icon" href="{{StaticUrlPrefix}}/img/favicon.png"> | |||
| <link rel="mask-icon" href="{{StaticUrlPrefix}}/img/openi-safari.svg" color="#609926"> | |||
| @@ -42,7 +42,8 @@ | |||
| <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | |||
| {{if .IsOperator}} | |||
| <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> | |||
| {{/* <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> */}} | |||
| <a class="item" href="{{AppSubUrl}}/kanban/index.html" target="_blank" rel="opener">{{.i18n.Tr "explore.data_analysis"}}</a> | |||
| {{end}} | |||
| <a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi.repo"}}</a> | |||
| </div> | |||
| @@ -73,7 +74,8 @@ | |||
| <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | |||
| {{if .IsOperator}} | |||
| <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> | |||
| {{/* <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> */}} | |||
| <a class="item" href="{{AppSubUrl}}/kanban/index.html" target="_blank" rel="opener">{{.i18n.Tr "explore.data_analysis"}}</a> | |||
| {{end}} | |||
| <a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi.repo"}}</a> | |||
| </div> | |||
| @@ -41,7 +41,8 @@ | |||
| <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | |||
| {{if .IsOperator}} | |||
| <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> | |||
| {{/* <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> */}} | |||
| <a class="item" href="{{AppSubUrl}}/kanban/index.html" target="_blank" rel="opener">{{.i18n.Tr "explore.data_analysis"}}</a> | |||
| {{end}} | |||
| <a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi.repo"}}</a> | |||
| </div> | |||
| @@ -71,7 +72,8 @@ | |||
| <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | |||
| {{if .IsOperator}} | |||
| <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> | |||
| {{/* <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> */}} | |||
| <a class="item" href="{{AppSubUrl}}/kanban/index.html" target="_blank" rel="opener">{{.i18n.Tr "explore.data_analysis"}}</a> | |||
| {{end}} | |||
| <a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi.repo"}}</a> | |||
| </div> | |||
| @@ -33,7 +33,8 @@ | |||
| <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | |||
| {{if .IsOperator}} | |||
| <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> | |||
| {{/* <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> */}} | |||
| <a class="item" href="{{AppSubUrl}}/kanban/index.html" target="_blank" rel="opener">{{.i18n.Tr "explore.data_analysis"}}</a> | |||
| {{end}} | |||
| <a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi.repo"}}</a> | |||
| </div> | |||
| @@ -64,7 +65,8 @@ | |||
| <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | |||
| {{if .IsOperator}} | |||
| <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> | |||
| {{/* <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> */}} | |||
| <a class="item" href="{{AppSubUrl}}/kanban/index.html" target="_blank" rel="opener">{{.i18n.Tr "explore.data_analysis"}}</a> | |||
| {{end}} | |||
| <a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi.repo"}}</a> | |||
| </div> | |||
| @@ -43,7 +43,8 @@ | |||
| <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | |||
| {{if .IsOperator}} | |||
| <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> | |||
| {{/* <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> */}} | |||
| <a class="item" href="{{AppSubUrl}}/kanban/index.html" target="_blank" rel="opener">{{.i18n.Tr "explore.data_analysis"}}</a> | |||
| {{end}} | |||
| <a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi.repo"}}</a> | |||
| </div> | |||
| @@ -74,7 +75,8 @@ | |||
| <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | |||
| {{if .IsOperator}} | |||
| <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> | |||
| {{/* <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> */}} | |||
| <a class="item" href="{{AppSubUrl}}/kanban/index.html" target="_blank" rel="opener">{{.i18n.Tr "explore.data_analysis"}}</a> | |||
| {{end}} | |||
| <a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi.repo"}}</a> | |||
| </div> | |||
| @@ -109,6 +109,11 @@ | |||
| ], | |||
| {{end}} | |||
| }; | |||
| {{if .IsSigned}} | |||
| window.sessionStorage.setItem('_csrf', '{{.CsrfToken}}'); | |||
| {{else}} | |||
| window.sessionStorage.removeItem('_csrf'); | |||
| {{end}} | |||
| </script> | |||
| <link rel="shortcut icon" href="{{StaticUrlPrefix}}/img/favicon.png"> | |||
| <link rel="mask-icon" href="{{StaticUrlPrefix}}/img/openi-safari.svg" color="#609926"> | |||
| @@ -24,9 +24,9 @@ | |||
| <div class="ui sixteen wide mobile ten wide tablet ten wide computer colum"> | |||
| {{range .Datasets}} | |||
| <div class="item"> | |||
| <div class="ui header"> | |||
| <a class="name" href="{{.Repo.Link}}/datasets"> | |||
| {{.Repo.OwnerName}} / {{.Repo.Alias}} | |||
| <div class="ui header" style="display: flex;"> | |||
| <a class="name dataset-title-a" title="{{.Title}}" href="{{.Repo.Link}}/datasets"> | |||
| {{.Title}} | |||
| </a> | |||
| <div class="ui right metas"> | |||
| {{if .Task}} | |||
| @@ -40,7 +40,7 @@ | |||
| </div> | |||
| <div class="description"> | |||
| {{if .Description}} | |||
| <p class="has-emoji">{{.Description}}</p> | |||
| <p class="has-emoji" style="word-break: break-all;">{{.Description}}</p> | |||
| {{else if .Repo.DescriptionHTML}} | |||
| <p class="has-emoji">{{.Repo.DescriptionHTML}}</p> | |||
| {{end}} | |||
| @@ -53,4 +53,7 @@ | |||
| </div> | |||
| {{end}} | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <script> | |||
| console.log({{.Datasets}}) | |||
| </script> | |||
| @@ -48,7 +48,7 @@ | |||
| <button class="ui green button"> | |||
| {{.i18n.Tr "org.create_org"}} | |||
| </button> | |||
| <a class="ui button" href="{{AppSubUrl}}/">{{.i18n.Tr "cancel"}}</a> | |||
| <a class="ui button" href="javascript:history.go(-1)">{{.i18n.Tr "cancel"}}</a> | |||
| </div> | |||
| </div> | |||
| </form> | |||
| @@ -353,7 +353,15 @@ | |||
| <td class="ti-text-form-content"> | |||
| <div class="text-span text-span-w" id="{{.VersionName}}-mirror"> | |||
| {{.Image}} | |||
| <span class="ui poping up clipboard" title="{{.Image}}" data-position="top center" id="clipboard-btn" style="cursor:pointer" | |||
| data-clipboard-text="{{.Image}}" | |||
| data-success="{{$.i18n.Tr "repo.copy_link_success"}}" | |||
| data-error="{{$.i18n.Tr "repo.copy_link_error"}}" | |||
| data-content="{{$.i18n.Tr "repo.copy_link"}}" | |||
| data-variation="inverted tiny" | |||
| > | |||
| {{.Image}} | |||
| </span> | |||
| </div> | |||
| </td> | |||
| </tr> | |||
| @@ -350,7 +350,7 @@ | |||
| loadCheckpointList(dataID).then((res)=>{ | |||
| res.forEach(element => { | |||
| const ckptSuffix = element.FileName.split(".") | |||
| const loadCheckpointFile = ['ckpt','pb','h5','json','pkl','pth','t7'] | |||
| const loadCheckpointFile = ['ckpt','pb','h5','json','pkl','pth','t7','pdparams','onnx','pbtxt','keras','mlmodel','cfg','pt'] | |||
| if(!element.IsDir && loadCheckpointFile.includes(ckptSuffix[ckptSuffix.length-1])){ | |||
| html += `<div class="item" data-value=${element.FileName}>${element.FileName}</div>` | |||
| } | |||
| @@ -444,7 +444,7 @@ | |||
| identifier : 'display_job_name', | |||
| rules: [ | |||
| { | |||
| type: 'regExp[/^[a-zA-Z0-9-_]{1,64}[^-]$/]', | |||
| type: 'regExp[/^[a-zA-Z0-9-_]{1,64}[a-zA-Z0-9_]$/]', | |||
| } | |||
| ] | |||
| }, | |||
| @@ -495,8 +495,8 @@ | |||
| document.getElementById("mask").style.display = "none" | |||
| } | |||
| } | |||
| validate(); | |||
| $('.ui.create_train_job.green.button').click(function(e) { | |||
| send_run_para() | |||
| validate() | |||
| }) | |||
| </script> | |||
| @@ -381,7 +381,15 @@ | |||
| <td class="ti-text-form-content"> | |||
| <div class="text-span text-span-w" id="{{.VersionName}}-mirror"> | |||
| {{.Image}} | |||
| <span class="ui poping up clipboard" title="{{.Image}}" data-position="top center" id="clipboard-btn" style="cursor:pointer" | |||
| data-clipboard-text="{{.Image}}" | |||
| data-success="{{$.i18n.Tr "repo.copy_link_success"}}" | |||
| data-error="{{$.i18n.Tr "repo.copy_link_error"}}" | |||
| data-content="{{$.i18n.Tr "repo.copy_link"}}" | |||
| data-variation="inverted tiny" | |||
| > | |||
| {{.Image}} | |||
| </span> | |||
| </div> | |||
| </td> | |||
| </tr> | |||
| @@ -294,6 +294,27 @@ | |||
| context.value = '' | |||
| $(".icon.icons").css("visibility", "hidden") | |||
| } | |||
| function validate(){ | |||
| $('.ui.form').form({ | |||
| on: 'blur', | |||
| fields: { | |||
| display_job_name:{ | |||
| identifier : 'display_job_name', | |||
| rules: [ | |||
| { | |||
| type: 'regExp[/^[a-z0-9][a-z0-9-_]{1,34}[a-z0-9-]$/]', | |||
| } | |||
| ] | |||
| }, | |||
| }, | |||
| onSuccess: function(){ | |||
| }, | |||
| onFailure: function(e){ | |||
| return false; | |||
| } | |||
| }) | |||
| } | |||
| validate(); | |||
| form.onsubmit = function (e) { | |||
| let value_task = $("input[name='display_job_name']").val() | |||
| let value_image = $("input[name='image']").val() | |||
| @@ -392,7 +392,15 @@ | |||
| <td class="ti-text-form-content"> | |||
| <div class="text-span text-span-w" id="{{.VersionName}}-mirror"> | |||
| {{.Image}} | |||
| <span class="ui poping up clipboard" title="{{.Image}}" data-position="top center" id="clipboard-btn" style="cursor:pointer" | |||
| data-clipboard-text="{{.Image}}" | |||
| data-success="{{$.i18n.Tr "repo.copy_link_success"}}" | |||
| data-error="{{$.i18n.Tr "repo.copy_link_error"}}" | |||
| data-content="{{$.i18n.Tr "repo.copy_link"}}" | |||
| data-variation="inverted tiny" | |||
| > | |||
| {{.Image}} | |||
| </span> | |||
| </div> | |||
| </td> | |||
| </tr> | |||
| @@ -497,8 +497,8 @@ | |||
| msg = JSON.stringify(msg) | |||
| $('#store_run_para').val(msg) | |||
| } | |||
| validate(); | |||
| $('.ui.create_train_job.green.button').click(function (e) { | |||
| send_run_para() | |||
| validate() | |||
| send_run_para() | |||
| }) | |||
| </script> | |||
| @@ -384,7 +384,15 @@ | |||
| <td class="ti-text-form-content"> | |||
| <div class="text-span text-span-w" id="{{.VersionName}}-mirror"> | |||
| {{.Image}} | |||
| <span class="ui poping up clipboard" title="{{.Image}}" data-position="top center" id="clipboard-btn" style="cursor:pointer" | |||
| data-clipboard-text="{{.Image}}" | |||
| data-success="{{$.i18n.Tr "repo.copy_link_success"}}" | |||
| data-error="{{$.i18n.Tr "repo.copy_link_error"}}" | |||
| data-content="{{$.i18n.Tr "repo.copy_link"}}" | |||
| data-variation="inverted tiny" | |||
| > | |||
| {{.Image}} | |||
| </span> | |||
| </div> | |||
| </td> | |||
| </tr> | |||
| @@ -176,7 +176,7 @@ | |||
| <button class="ui green button" id="submit_reponame"> | |||
| {{.i18n.Tr "repo.create_repo"}} | |||
| </button> | |||
| <a class="ui button" href="{{AppSubUrl}}/">{{.i18n.Tr "cancel"}}</a> | |||
| <a class="ui button" href="javascript:history.go(-1)">{{.i18n.Tr "cancel"}}</a> | |||
| </div> | |||
| </div> | |||
| </form> | |||
| @@ -386,7 +386,7 @@ | |||
| {{$.CsrfTokenHtml}} | |||
| {{if .CanDel}} | |||
| <a id="ai-stop-{{.Cloudbrain.ID}}" | |||
| class='ui basic ai_stop {{if eq .Status "STOPPED" "FAILED" "START_FAILED" "STOPPING" "CREATING" "STARTING" "SUCCEEDED" "CREATE_FAILED"}}disabled {{else}}blue {{end}}button' | |||
| class='ui basic ai_stop {{if eq .Status "STOPPED" "FAILED" "START_FAILED" "STOPPING" "CREATING" "STARTING" "SUCCEEDED" "CREATE_FAILED" "DELETED"}}disabled {{else}}blue {{end}}button' | |||
| data-repopath="{{$.RepoLink}}{{if eq .ComputeResource "CPU/GPU"}}/cloudbrain{{else}}/modelarts/notebook{{end}}/{{.Cloudbrain.ID}}/stop" | |||
| data-jobid="{{.Cloudbrain.ID}}"> | |||
| {{$.i18n.Tr "repo.stop"}} | |||
| @@ -405,7 +405,7 @@ | |||
| {{$.CsrfTokenHtml}} | |||
| {{if .CanDel}} | |||
| <a id="ai-delete-{{.Cloudbrain.ID}}" | |||
| class='ui basic ai_delete {{if eq .Status "STOPPED" "FAILED" "START_FAILED" "SUCCEEDED" "CREATE_FAILED"}}blue {{else}}disabled {{end}}button' | |||
| class='ui basic ai_delete {{if eq .Status "STOPPED" "FAILED" "START_FAILED" "SUCCEEDED" "CREATE_FAILED" "DELETED"}}blue {{else}}disabled {{end}}button' | |||
| style="border-radius: .28571429rem;"> | |||
| {{$.i18n.Tr "repo.delete"}} | |||
| </a> | |||
| @@ -427,6 +427,7 @@ | |||
| {{if .CanDebug}} | |||
| <a id="model-image-{{.Cloudbrain.ID}}" | |||
| class='imageBtn ui basic {{if ne .Status "RUNNING"}}disabled {{else}}blue {{end}}button' | |||
| target="_blank" | |||
| href="{{$.RepoLink}}/cloudbrain/{{.Cloudbrain.ID}}/commit_image">{{$.i18n.Tr "repo.submit_image"}}</a> | |||
| {{else}} | |||
| <a | |||
| @@ -444,8 +444,8 @@ | |||
| msg = JSON.stringify(msg) | |||
| $('#store_run_para').val(msg) | |||
| } | |||
| validate(); | |||
| $('.ui.create_train_job.green.button').click(function(e) { | |||
| send_run_para() | |||
| validate() | |||
| }) | |||
| </script> | |||
| @@ -475,9 +475,9 @@ | |||
| $("input#trainjob_work_server_num").val(val_server_num_select) | |||
| } | |||
| validate(); | |||
| $('.ui.create_train_job.green.button').click(function(e) { | |||
| get_name() | |||
| send_run_para() | |||
| validate() | |||
| }) | |||
| </script> | |||
| @@ -11,7 +11,7 @@ | |||
| {{template "base/alert" .}} | |||
| <div class="inline required field {{if .Err_CloneAddr}}error{{end}}"> | |||
| <label for="clone_addr">{{.i18n.Tr "repo.migrate.clone_address"}}</label> | |||
| <input id="clone_addr" name="clone_addr" value="{{.clone_addr}}" autofocus required> | |||
| <input id="clone_addr" name="clone_addr" value="{{.clone_addr}}" autofocus required autocomplete="off" /> | |||
| <span class="help"> | |||
| {{.i18n.Tr "repo.migrate.clone_address_desc"}}{{if .ContextUser.CanImportLocal}} {{.i18n.Tr "repo.migrate.clone_local_path"}}{{end}} | |||
| <br/>{{.i18n.Tr "repo.migrate.migrate_items_options"}} | |||
| @@ -102,7 +102,7 @@ | |||
| <button class="ui green button" id="submit_reponame"> | |||
| {{.i18n.Tr "repo.migrate_repo"}} | |||
| </button> | |||
| <a class="ui button" href="{{AppSubUrl}}/">{{.i18n.Tr "cancel"}}</a> | |||
| <a class="ui button" href="javascript:history.go(-1)">{{.i18n.Tr "cancel"}}</a> | |||
| </div> | |||
| </div> | |||
| </form> | |||
| @@ -368,7 +368,7 @@ | |||
| loadCheckpointList(dataID).then((res)=>{ | |||
| res.forEach(element => { | |||
| const ckptSuffix = element.FileName.split(".") | |||
| const loadCheckpointFile = ['ckpt','pb','h5','json','pkl','pth','t7'] | |||
| const loadCheckpointFile = ['ckpt','pb','h5','json','pkl','pth','t7','pdparams','onnx','pbtxt','keras','mlmodel','cfg','pt'] | |||
| if(!element.IsDir && loadCheckpointFile.includes(ckptSuffix[ckptSuffix.length-1])){ | |||
| html += `<div class="item" data-value=${element.FileName}>${element.FileName}</div>` | |||
| } | |||
| @@ -468,7 +468,7 @@ | |||
| identifier : 'display_job_name', | |||
| rules: [ | |||
| { | |||
| type: 'regExp[/^[a-zA-Z0-9-_]{1,64}[^-]$/]', | |||
| type: 'regExp[/^[a-zA-Z0-9-_]{1,64}[a-zA-Z0-9_]$/]', | |||
| } | |||
| ] | |||
| }, | |||
| @@ -519,9 +519,9 @@ | |||
| document.getElementById("mask").style.display = "none" | |||
| } | |||
| } | |||
| validate(); | |||
| $('.ui.create_train_job.green.button').click(function(e) { | |||
| send_run_para() | |||
| get_name() | |||
| validate() | |||
| }) | |||
| </script> | |||
| @@ -110,6 +110,28 @@ | |||
| $('#messageInfo').css('display','none') | |||
| function validate(){ | |||
| $('.ui.form').form({ | |||
| on: 'blur', | |||
| fields: { | |||
| display_job_name:{ | |||
| identifier : 'display_job_name', | |||
| rules: [ | |||
| { | |||
| type: 'regExp[/^[a-z0-9][a-z0-9-_]{1,36}$/]', | |||
| } | |||
| ] | |||
| }, | |||
| }, | |||
| onSuccess: function(){ | |||
| }, | |||
| onFailure: function(e){ | |||
| return false; | |||
| } | |||
| }) | |||
| } | |||
| validate(); | |||
| form.onsubmit = function(e){ | |||
| let value_task = $("input[name='display_job_name']").val() | |||
| @@ -359,7 +359,15 @@ | |||
| <td class="ti-text-form-content"> | |||
| <div class="text-span text-span-w" id="{{.VersionName}}-mirror"> | |||
| {{.Image}} | |||
| <span class="ui poping up clipboard" title="{{.Image}}" data-position="top center" id="clipboard-btn" style="cursor:pointer" | |||
| data-clipboard-text="{{.Image}}" | |||
| data-success="{{$.i18n.Tr "repo.copy_link_success"}}" | |||
| data-error="{{$.i18n.Tr "repo.copy_link_error"}}" | |||
| data-content="{{$.i18n.Tr "repo.copy_link"}}" | |||
| data-variation="inverted tiny" | |||
| > | |||
| {{.Image}} | |||
| </span> | |||
| </div> | |||
| </td> | |||
| </tr> | |||
| @@ -528,9 +528,9 @@ | |||
| $("input#trainjob_work_server_num").val(val_server_num_select) | |||
| } | |||
| validate(); | |||
| $('.ui.create_train_job.green.button').click(function (e) { | |||
| get_name() | |||
| send_run_para() | |||
| validate() | |||
| }) | |||
| </script> | |||
| @@ -270,7 +270,7 @@ | |||
| {{end}} | |||
| {{if .CanDel}} | |||
| <a class="ti-action-menu-item stop-show-version {{if eq .Status "KILLED" "FAILED" "START_FAILED" "KILLING" "COMPLETED"}}disabled {{end}}" | |||
| <a class="ti-action-menu-item stop-show-version {{if eq .Status "KILLED" "FAILED" "START_FAILED" "KILLING" "COMPLETED" "SUCCEEDED" "STOPPED"}}disabled {{end}}" | |||
| id="{{.VersionName}}-stop" | |||
| data-jobid="{{.JobID}}" | |||
| data-repopath="{{$.RepoRelPath}}/modelarts/train-job" | |||
| @@ -6,7 +6,8 @@ | |||
| text-align: right; | |||
| } | |||
| .inline .ui.dropdown .text { | |||
| color: rgba(0, 0, 0, .87) !important | |||
| color: rgba(0, 0, 0, .87) !important; | |||
| max-width: 360px; | |||
| } | |||
| .newtext{ | |||
| left: 15px !important | |||
| @@ -361,4 +361,4 @@ | |||
| </div> | |||
| </div> | |||
| </div> | |||
| {{template "base/footer" .}} | |||
| {{template "base/footer" .}} | |||
| @@ -6,7 +6,7 @@ | |||
| ref="table" | |||
| :data="tableData" | |||
| style="min-width: 100%" | |||
| row-key="ID" | |||
| row-key="rowKey" | |||
| lazy | |||
| :load="load" | |||
| :tree-props="{children: 'Children', hasChildren: 'hasChildren'}" | |||
| @@ -171,6 +171,7 @@ export default { | |||
| tableData[i].EngineName = this.getEngineName(tableData[i]) | |||
| tableData[i].ComputeResource = TrainTaskInfo.ComputeResource | |||
| tableData[i].cName=tableData[i].Name | |||
| tableData[i].rowKey = tableData[i].ID + Math.random() | |||
| tableData[i].Name='' | |||
| tableData[i].VersionCount = '' | |||
| tableData[i].Children = true | |||
| @@ -310,18 +311,18 @@ export default { | |||
| const store = this.$refs.table.store | |||
| if(!this.loadNodeMap.get(row.cName)){ | |||
| const parent = store.states.data | |||
| const index = parent.findIndex(child => child.ID == row.ID) | |||
| const index = parent.findIndex(child => child.rowKey == row.rowKey) | |||
| this.getModelList() | |||
| }else{ | |||
| let {tree,treeNode,resolve} = this.loadNodeMap.get(row.cName) | |||
| const keys = Object.keys(store.states.lazyTreeNodeMap); | |||
| if(keys.includes(row.ID)){ | |||
| if(keys.includes(row.rowKey)){ | |||
| this.getModelList() | |||
| }else{ | |||
| let parentRow = store.states.data.find(child => child.cName == row.cName); | |||
| let childrenIndex = store.states.lazyTreeNodeMap[parentRow.ID].findIndex(child => child.ID == row.ID) | |||
| let childrenIndex = store.states.lazyTreeNodeMap[parentRow.rowKey].findIndex(child => child.rowKey == row.rowKey) | |||
| parentRow.VersionCount = parentRow.VersionCount-1 | |||
| const parent = store.states.lazyTreeNodeMap[parentRow.ID] | |||
| const parent = store.states.lazyTreeNodeMap[parentRow.rowKey] | |||
| if(parent.length===1){ | |||
| this.getModelList() | |||
| }else{ | |||
| @@ -379,8 +380,8 @@ export default { | |||
| } | |||
| }, | |||
| getModelList(){ | |||
| try { | |||
| this.$refs.table.store.states.lazyTreeNodeMap = {} | |||
| try { | |||
| this.loadNodeMap.clear(); | |||
| this.$axios.get(location.href+'_api',{ | |||
| params:this.params | |||
| }).then((res)=>{ | |||
| @@ -391,6 +392,7 @@ export default { | |||
| for(let i=0;i<this.tableData.length;i++){ | |||
| TrainTaskInfo = JSON.parse(this.tableData[i].TrainTaskInfo) | |||
| this.tableData[i].cName=this.tableData[i].Name | |||
| this.tableData[i].rowKey=this.tableData[i].ID + Math.random() | |||
| this.tableData[i].EngineName = this.getEngineName(this.tableData[i]) | |||
| this.tableData[i].ComputeResource = TrainTaskInfo.ComputeResource | |||
| this.tableData[i].hasChildren = res.data.data[i].VersionCount===1 ? false : true | |||
| @@ -215,16 +215,16 @@ | |||
| <div style="display:flex;align-items: center;justify-content: center;"> | |||
| <span v-if="scope.row.isPrivate" style="color: rgb(250, 140, 22);">私有</span> | |||
| <span v-else style="color: rgb(19, 194, 141);">公开</span> | |||
| <el-tooltip class="item" effect="dark" content="镜像提交中..." placement="top"> | |||
| <i v-if="scope.row.status===0" class="CREATING" style="margin-left:0.3rem"></i> | |||
| <el-tooltip v-if="scope.row.status===0" class="item" effect="dark" content="镜像提交中..." placement="top"> | |||
| <i class="CREATING" style="margin-left:0.3rem"></i> | |||
| </el-tooltip> | |||
| <el-tooltip class="item" effect="dark" content="检测提交镜像是否大小超过20G!" placement="top"> | |||
| <i v-if="scope.row.status===2" class="FAILED" style="margin-left:0.3rem"></i> | |||
| <el-tooltip v-if="scope.row.status===2" class="item" effect="dark" content="检测提交镜像是否大小超过20G!" placement="top"> | |||
| <i class="FAILED" style="margin-left:0.3rem"></i> | |||
| </el-tooltip> | |||
| <el-tooltip class="item" effect="dark" content="镜像提交成功" placement="top"> | |||
| <i v-if="scope.row.status===1" class="SUCCEEDED" style="margin-left:0.3rem"></i> | |||
| <el-tooltip v-if="scope.row.status===1" class="item" effect="dark" content="镜像提交成功" placement="top"> | |||
| <i class="SUCCEEDED" style="margin-left:0.3rem"></i> | |||
| </el-tooltip> | |||
| </div> | |||
| @@ -473,6 +473,7 @@ export default { | |||
| tableDataCustom: [], | |||
| starCustom:[], | |||
| loadingCustom:false, | |||
| refreshCustomTimer: null, | |||
| currentPageStar:1, | |||
| pageSizeStar:10, | |||
| @@ -485,6 +486,7 @@ export default { | |||
| methods: { | |||
| handleClick(tab, event) { | |||
| this.search = '' | |||
| this.stopImageListCustomRefresh(); | |||
| if(tab.name=="first"){ | |||
| this.paramsPublic.q = '' | |||
| this.getImageListPublic() | |||
| @@ -560,9 +562,31 @@ export default { | |||
| }); | |||
| this.loadingCustom = false | |||
| this.getImageListCustomRefresh() | |||
| }) | |||
| }, | |||
| getImageListCustomRefresh() { | |||
| this.stopImageListCustomRefresh(); | |||
| this.refreshCustomTimer = setInterval(() => { | |||
| this.tableDataCustom.forEach(item => { | |||
| if (item.status === 0) { | |||
| this.$axios.get(`/image/${item.id}`, {}).then((res) => { | |||
| const newData = res.data; | |||
| this.tableDataCustom.forEach(it => { | |||
| if (it.id === newData.id) { | |||
| it.status = newData.status; | |||
| } | |||
| }); | |||
| }) | |||
| } | |||
| }); | |||
| }, 5000); | |||
| }, | |||
| stopImageListCustomRefresh() { | |||
| this.refreshCustomTimer && clearInterval(this.refreshCustomTimer); | |||
| }, | |||
| getImageListStar(){ | |||
| this.loadingStar = true | |||
| this.$axios.get('/explore/images/star',{ | |||
| @@ -715,8 +739,10 @@ export default { | |||
| else{ | |||
| this.getImageListPublic() | |||
| } | |||
| }, | |||
| beforeDestroy() { | |||
| this.stopImageListCustomRefresh(); | |||
| } | |||
| }; | |||
| </script> | |||
| @@ -1,23 +1,37 @@ | |||
| export default async function initClipboard() { | |||
| const els = document.querySelectorAll('.clipboard'); | |||
| const els = document.querySelectorAll(".clipboard"); | |||
| if (!els || !els.length) return; | |||
| const { default: ClipboardJS } = await import(/* webpackChunkName: "clipboard" */'clipboard'); | |||
| const { default: ClipboardJS } = await import( | |||
| /* webpackChunkName: "clipboard" */ "clipboard" | |||
| ); | |||
| const clipboard = new ClipboardJS(els); | |||
| clipboard.on('success', (e) => { | |||
| clipboard.on("success", (e) => { | |||
| e.clearSelection(); | |||
| $(`#${e.trigger.getAttribute('id')}`).popup('destroy'); | |||
| e.trigger.setAttribute('data-content', e.trigger.getAttribute('data-success')); | |||
| $(`#${e.trigger.getAttribute('id')}`).popup('show'); | |||
| e.trigger.setAttribute('data-content', e.trigger.getAttribute('data-original')); | |||
| $(`#${e.trigger.getAttribute("id")}`).popup("destroy"); | |||
| e.trigger.setAttribute( | |||
| "data-content", | |||
| e.trigger.getAttribute("data-success") | |||
| ); | |||
| $(`#${e.trigger.getAttribute("id")}`).popup("show"); | |||
| e.trigger.setAttribute( | |||
| "data-content", | |||
| e.trigger.getAttribute("data-original") | |||
| ); | |||
| }); | |||
| clipboard.on('error', (e) => { | |||
| $(`#${e.trigger.getAttribute('id')}`).popup('destroy'); | |||
| e.trigger.setAttribute('data-content', e.trigger.getAttribute('data-error')); | |||
| $(`#${e.trigger.getAttribute('id')}`).popup('show'); | |||
| e.trigger.setAttribute('data-content', e.trigger.getAttribute('data-original')); | |||
| clipboard.on("error", (e) => { | |||
| $(`#${e.trigger.getAttribute("id")}`).popup("destroy"); | |||
| e.trigger.setAttribute( | |||
| "data-content", | |||
| e.trigger.getAttribute("data-error") | |||
| ); | |||
| $(`#${e.trigger.getAttribute("id")}`).popup("show"); | |||
| e.trigger.setAttribute( | |||
| "data-content", | |||
| e.trigger.getAttribute("data-original") | |||
| ); | |||
| }); | |||
| } | |||
| @@ -168,14 +168,16 @@ export default async function initCloudrainSow() { | |||
| let downloadFlag = $(this).data("download-flag") || ""; | |||
| let gpuFlag = $(this).data("gpu-flag") || ""; | |||
| let version_name = $(this).data("version"); | |||
| let parents = $(this).data("parents") || ""; | |||
| let filename = $(this).data("filename") || ""; | |||
| let parents = $(this).data("parents"); | |||
| let filename = $(this).data("filename"); | |||
| let init = $(this).data("init") || ""; | |||
| let path = $(this).data("path"); | |||
| let url = `/api/v1/repos${path}?version_name=${version_name}&parentDir=${parents}`; | |||
| $.get(url, (data) => { | |||
| $(`#dir_list${version_name}`).empty(); | |||
| renderDir(path, data, version_name, downloadFlag, gpuFlag); | |||
| if(data.Dirs){ | |||
| renderDir(path, data, version_name, downloadFlag, gpuFlag); | |||
| } | |||
| if (init === "init") { | |||
| $(`input[name=model${version_name}]`).val(""); | |||
| $(`input[name=modelback${version_name}]`).val(version_name); | |||
| @@ -189,7 +191,7 @@ export default async function initCloudrainSow() { | |||
| htmlBread += "<div class='divider'> / </div>"; | |||
| $(`#file_breadcrumb${version_name}`).append(htmlBread); | |||
| } else { | |||
| renderBrend(path, version_name, parents, filename, init); | |||
| renderBrend(path, version_name, parents, filename, init, downloadFlag,gpuFlag); | |||
| } | |||
| }).fail(function (err) { | |||
| console.log(err, version_name); | |||
| @@ -217,7 +219,15 @@ export default async function initCloudrainSow() { | |||
| size = size.toFixed(0); //保留的小数位数 | |||
| return size + unitArr[index]; | |||
| } | |||
| function renderBrend(path, version_name, parents, filename, init) { | |||
| function renderBrend( | |||
| path, | |||
| version_name, | |||
| parents, | |||
| filename, | |||
| init, | |||
| downloadFlag, | |||
| gpuFlag | |||
| ) { | |||
| if (init == "folder") { | |||
| let htmlBrend = ""; | |||
| let sectionName = $( | |||
| @@ -227,11 +237,11 @@ export default async function initCloudrainSow() { | |||
| let filename1 = $(`input[name=modelback${version_name}]`).val(); | |||
| if (parents1 === "") { | |||
| $(`#file_breadcrumb${version_name} .active.section`).replaceWith( | |||
| `<a class='section load-model-file' data-path='${path}' data-version='${version_name}' data-parents='${parents1}' data-filename='' data-init='init'>${sectionName}</a>` | |||
| `<a class='section load-model-file' data-download-flag='${downloadFlag}' data-gpu-flag='${gpuFlag}' data-path='${path}' data-version='${version_name}' data-parents='${parents1}' data-filename='' data-init='init'>${sectionName}</a>` | |||
| ); | |||
| } else { | |||
| $(`#file_breadcrumb${version_name} .active.section`).replaceWith( | |||
| `<a class='section load-model-file' data-path='${path}' data-version='${version_name}' data-parents='${parents1}' data-filename='${filename1}'>${sectionName}</a>` | |||
| `<a class='section load-model-file' data-download-flag='${downloadFlag}' data-gpu-flag='${gpuFlag}' data-path='${path}' data-version='${version_name}' data-parents='${parents1}' data-filename='${filename1}'>${sectionName}</a>` | |||
| ); | |||
| } | |||
| @@ -272,7 +282,7 @@ export default async function initCloudrainSow() { | |||
| html += "<span class='octicon octicon-file-directory'>"; | |||
| html += "</span>"; | |||
| if (data.Dirs[i].IsDir) { | |||
| html += `<a class='load-model-file' data-path='${path}' data-version='${version_name}' data-parents='${data.Dirs[i].ParenDir}' data-filename='${data.Dirs[i].FileName}' data-init='folder'>`; | |||
| html += `<a class='load-model-file' data-download-flag='${downloadFlag}' data-gpu-flag='${gpuFlag}' data-path='${path}' data-version='${version_name}' data-parents='${data.Dirs[i].ParenDir}' data-filename='${data.Dirs[i].FileName}' data-init='folder'>`; | |||
| html += | |||
| "<span class='fitted'><i class='folder icon' width='16' height='16' aria-hidden='true'></i>" + | |||
| data.Dirs[i].FileName + | |||
| @@ -2950,13 +2950,13 @@ $(document).ready(async () => { | |||
| } | |||
| const $cloneAddr = $("#clone_addr"); | |||
| $cloneAddr.on("change", () => { | |||
| $cloneAddr.on("input change", () => { | |||
| const $repoName = $("#alias"); | |||
| const $owner = $("#ownerDropdown div.text").attr("title"); | |||
| const $urlAdd = | |||
| location.href.split("/")[0] + "//" + location.href.split("/")[2]; | |||
| if ($cloneAddr.val().length > 0 && $repoName.val().length === 0) { | |||
| // Only modify if repo_name input is blank | |||
| if ($cloneAddr.val().length > 0 /* && $repoName.val().length === 0 */) { | |||
| // modify when clone address change | |||
| const repoValue = $cloneAddr.val().match(/^(.*\/)?((.+?)(\.git)?)$/)[3]; | |||
| $repoName.val($cloneAddr.val().match(/^(.*\/)?((.+?)(\.git)?)$/)[3]); | |||
| $.get( | |||
| @@ -140,27 +140,26 @@ | |||
| border: 1px solid #ffffff; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| .item { | |||
| border-bottom: 1px solid rgba(34,36,38,.15); | |||
| border-bottom: 1px solid rgba(34, 36, 38, 0.15); | |||
| .ui.buttons { | |||
| .button { | |||
| box-shadow: none !important; | |||
| } | |||
| } | |||
| } | |||
| .ui.grid > .row { | |||
| align-items: center; | |||
| } | |||
| .title { | |||
| font-size: 16px; | |||
| font-weight: bold; | |||
| margin: 0 6px; | |||
| margin: 0 6px; | |||
| overflow: hidden; | |||
| padding-right: 15px; | |||
| white-space: nowrap; | |||
| @@ -195,7 +194,15 @@ | |||
| .name { | |||
| word-break: break-all; | |||
| } | |||
| .dataset-title-a { | |||
| flex: 1; | |||
| overflow: hidden; | |||
| text-overflow: ellipsis; | |||
| min-width: 0; | |||
| word-break: inherit !important; | |||
| margin-right: 3rem; | |||
| white-space: nowrap; | |||
| } | |||
| .metas { | |||
| color: #888888; | |||
| font-size: 14px; | |||
| @@ -222,7 +229,7 @@ | |||
| } | |||
| } | |||
| } | |||
| .panel_creator_reponam{ | |||
| .panel_creator_reponam { | |||
| display: inline-block; | |||
| border-radius: 4px; | |||
| padding: 4px; | |||
| @@ -231,29 +238,28 @@ | |||
| background-color: rgba(161, 220, 255, 0.2); | |||
| color: #101010; | |||
| } | |||
| .panel_dataset_name{ | |||
| .panel_dataset_name { | |||
| font-size: 15px; | |||
| color: #0366D6; | |||
| color: #0366d6; | |||
| text-align: center; | |||
| margin-left: 1rem; | |||
| } | |||
| .panel_datset_desc{ | |||
| .panel_datset_desc { | |||
| white-space: nowrap; | |||
| display: inline-block; | |||
| overflow: hidden; | |||
| width: 90%; | |||
| text-overflow: ellipsis; | |||
| } | |||
| .el-dialog__body{ | |||
| padding-top:0 | |||
| .el-dialog__body { | |||
| padding-top: 0; | |||
| } | |||
| #dataset-base{ | |||
| .active{ | |||
| color: #0087f5!important; | |||
| border: 1px solid #0087f5!important; | |||
| #dataset-base { | |||
| .active { | |||
| color: #0087f5 !important; | |||
| border: 1px solid #0087f5 !important; | |||
| /* margin: -1px!important; */ | |||
| background: #fff!important; | |||
| background: #fff !important; | |||
| } | |||
| } | |||
| } | |||
| @@ -311,6 +311,7 @@ footer .column { | |||
| } | |||
| .FAILED, | |||
| .START_FAILED, | |||
| .DELETED, | |||
| .CREATE_FAILED { | |||
| display: inline-block; | |||
| width: 18px; | |||