| @@ -4,6 +4,7 @@ import ( | |||||
| "encoding/json" | "encoding/json" | ||||
| "errors" | "errors" | ||||
| "fmt" | "fmt" | ||||
| "path" | |||||
| "strconv" | "strconv" | ||||
| "strings" | "strings" | ||||
| "time" | "time" | ||||
| @@ -101,7 +102,8 @@ const ( | |||||
| ModelArtsTrainJobCheckRunningCompleted ModelArtsJobStatus = "CHECK_RUNNING_COMPLETED" //审核作业已经完成 | ModelArtsTrainJobCheckRunningCompleted ModelArtsJobStatus = "CHECK_RUNNING_COMPLETED" //审核作业已经完成 | ||||
| ModelArtsTrainJobCheckFailed ModelArtsJobStatus = "CHECK_FAILED" //审核作业失败 | ModelArtsTrainJobCheckFailed ModelArtsJobStatus = "CHECK_FAILED" //审核作业失败 | ||||
| DURATION_STR_ZERO = "00:00:00" | |||||
| DURATION_STR_ZERO = "00:00:00" | |||||
| CloudbrainKeyDuration = 24 * time.Hour | |||||
| //grampus | //grampus | ||||
| GrampusStatusPending = "pending" | GrampusStatusPending = "pending" | ||||
| @@ -187,6 +189,7 @@ type Cloudbrain struct { | |||||
| ModelName string //模型名称 | ModelName string //模型名称 | ||||
| ModelVersion string //模型版本 | ModelVersion string //模型版本 | ||||
| CkptName string //权重文件名称 | CkptName string //权重文件名称 | ||||
| PreTrainModelUrl string //预训练模型地址 | |||||
| ResultUrl string //推理结果的obs路径 | ResultUrl string //推理结果的obs路径 | ||||
| User *User `xorm:"-"` | User *User `xorm:"-"` | ||||
| @@ -278,7 +281,7 @@ func (task *Cloudbrain) IsRunning() bool { | |||||
| } | } | ||||
| func ConvertDurationToStr(duration int64) string { | func ConvertDurationToStr(duration int64) string { | ||||
| if duration == 0 { | |||||
| if duration <= 0 { | |||||
| return DURATION_STR_ZERO | return DURATION_STR_ZERO | ||||
| } | } | ||||
| return util.AddZero(duration/3600) + ":" + util.AddZero(duration%3600/60) + ":" + util.AddZero(duration%60) | return util.AddZero(duration/3600) + ":" + util.AddZero(duration%3600/60) + ":" + util.AddZero(duration%60) | ||||
| @@ -654,6 +657,8 @@ type FlavorInfo struct { | |||||
| UnitPrice int64 `json:"unitPrice"` | UnitPrice int64 `json:"unitPrice"` | ||||
| } | } | ||||
| type SpecialPools struct { | type SpecialPools struct { | ||||
| Pools []*SpecialPool `json:"pools"` | Pools []*SpecialPool `json:"pools"` | ||||
| } | } | ||||
| @@ -2295,9 +2300,10 @@ func GetCloudbrainByIds(ids []int64) ([]*Cloudbrain, error) { | |||||
| type DatasetInfo struct { | type DatasetInfo struct { | ||||
| DataLocalPath string | DataLocalPath string | ||||
| Name string | Name string | ||||
| FullName string | |||||
| } | } | ||||
| func GetDatasetInfo(uuidStr string) (map[string]DatasetInfo, string, error) { | |||||
| func GetDatasetInfo(uuidStr string, grampusType ...string) (map[string]DatasetInfo, string, error) { | |||||
| var datasetNames string | var datasetNames string | ||||
| uuids := strings.Split(uuidStr, ";") | uuids := strings.Split(uuidStr, ";") | ||||
| if len(uuids) > setting.MaxDatasetNum { | if len(uuids) > setting.MaxDatasetNum { | ||||
| @@ -2330,16 +2336,26 @@ func GetDatasetInfo(uuidStr string) (map[string]DatasetInfo, string, error) { | |||||
| return nil, datasetNames, errors.New("the dataset name is same") | return nil, datasetNames, errors.New("the dataset name is same") | ||||
| } | } | ||||
| } | } | ||||
| var dataLocalPath string | |||||
| if len(grampusType) > 0 { | |||||
| if grampusType[0] == GPU { | |||||
| dataLocalPath = setting.Attachment.Minio.BasePath + path.Join(attach.UUID[0:1], attach.UUID[1:2]) + "/" + attach.UUID | |||||
| } else { | |||||
| dataLocalPath = setting.BasePath + path.Join(attach.UUID[0:1], attach.UUID[1:2]) + "/" + attach.UUID + "/" | |||||
| } | |||||
| dataLocalPath := setting.Attachment.Minio.RealPath + | |||||
| setting.Attachment.Minio.Bucket + "/" + | |||||
| setting.Attachment.Minio.BasePath + | |||||
| AttachmentRelativePath(attach.UUID) + | |||||
| attach.UUID | |||||
| } else { | |||||
| dataLocalPath = setting.Attachment.Minio.RealPath + | |||||
| setting.Attachment.Minio.Bucket + "/" + | |||||
| setting.Attachment.Minio.BasePath + | |||||
| AttachmentRelativePath(attach.UUID) + | |||||
| attach.UUID | |||||
| } | |||||
| datasetInfos[attach.UUID] = DatasetInfo{ | datasetInfos[attach.UUID] = DatasetInfo{ | ||||
| DataLocalPath: dataLocalPath, | DataLocalPath: dataLocalPath, | ||||
| Name: fileName, | Name: fileName, | ||||
| FullName: attach.Name, | |||||
| } | } | ||||
| if i == 0 { | if i == 0 { | ||||
| datasetNames = attach.Name | datasetNames = attach.Name | ||||
| @@ -34,6 +34,7 @@ type TaskDetail struct { | |||||
| CardDuration string `json:"CardDuration"` | CardDuration string `json:"CardDuration"` | ||||
| AiCenter string `json:"AiCenter"` | AiCenter string `json:"AiCenter"` | ||||
| FlavorName string `json:"FlavorName"` | FlavorName string `json:"FlavorName"` | ||||
| Spec *Specification `json:"Spec"` | |||||
| } | } | ||||
| func GetTodayCreatorCount(beginTime time.Time, endTime time.Time) (int64, error) { | func GetTodayCreatorCount(beginTime time.Time, endTime time.Time) (int64, error) { | ||||
| @@ -65,6 +65,19 @@ type TaskAndLimiterConfig struct { | |||||
| LimitConfig LimitConfig `xorm:"extends"` | LimitConfig LimitConfig `xorm:"extends"` | ||||
| } | } | ||||
| type PointRule struct { | |||||
| UserDailyLimit int64 | |||||
| TaskRules []TaskRule | |||||
| } | |||||
| type TaskRule struct { | |||||
| TaskCode string | |||||
| AwardType string | |||||
| AwardAmount int64 | |||||
| RefreshRate string | |||||
| LimitNum int64 | |||||
| } | |||||
| func (TaskAndLimiterConfig) TableName() string { | func (TaskAndLimiterConfig) TableName() string { | ||||
| return "task_config" | return "task_config" | ||||
| } | } | ||||
| @@ -23,6 +23,11 @@ type CreateCloudBrainForm struct { | |||||
| BootFile string `form:"boot_file"` | BootFile string `form:"boot_file"` | ||||
| Params string `form:"run_para_list"` | Params string `form:"run_para_list"` | ||||
| BranchName string `form:"branch_name"` | BranchName string `form:"branch_name"` | ||||
| ModelName string `form:"model_name"` | |||||
| ModelVersion string `form:"model_version"` | |||||
| CkptName string `form:"ckpt_name"` | |||||
| LabelName string `form:"label_names"` | |||||
| PreTrainModelUrl string `form:"pre_train_model_url"` | |||||
| DatasetName string `form:"dataset_name"` | DatasetName string `form:"dataset_name"` | ||||
| SpecId int64 `form:"spec_id"` | SpecId int64 `form:"spec_id"` | ||||
| } | } | ||||
| @@ -18,6 +18,11 @@ type CreateGrampusTrainJobForm struct { | |||||
| WorkServerNumber int `form:"work_server_number" binding:"Required"` | WorkServerNumber int `form:"work_server_number" binding:"Required"` | ||||
| Image string `form:"image"` | Image string `form:"image"` | ||||
| DatasetName string `form:"dataset_name"` | DatasetName string `form:"dataset_name"` | ||||
| ModelName string `form:"model_name"` | |||||
| ModelVersion string `form:"model_version"` | |||||
| CkptName string `form:"ckpt_name"` | |||||
| LabelName string `form:"label_names"` | |||||
| PreTrainModelUrl string `form:"pre_train_model_url"` | |||||
| SpecId int64 `form:"spec_id"` | SpecId int64 `form:"spec_id"` | ||||
| } | } | ||||
| @@ -48,6 +48,11 @@ type CreateModelArtsTrainJobForm struct { | |||||
| FlavorName string `form:"flaver_names" binding:"Required"` | FlavorName string `form:"flaver_names" binding:"Required"` | ||||
| EngineName string `form:"engine_names" binding:"Required"` | EngineName string `form:"engine_names" binding:"Required"` | ||||
| SpecId int64 `form:"spec_id" binding:"Required"` | SpecId int64 `form:"spec_id" binding:"Required"` | ||||
| ModelName string `form:"model_name"` | |||||
| ModelVersion string `form:"model_version"` | |||||
| CkptName string `form:"ckpt_name"` | |||||
| LabelName string `form:"label_names"` | |||||
| PreTrainModelUrl string `form:"pre_train_model_url"` | |||||
| } | } | ||||
| type CreateModelArtsInferenceJobForm struct { | type CreateModelArtsInferenceJobForm struct { | ||||
| @@ -1,10 +1,11 @@ | |||||
| package wechat | package wechat | ||||
| import ( | import ( | ||||
| "time" | |||||
| "code.gitea.io/gitea/modules/redis/redis_client" | "code.gitea.io/gitea/modules/redis/redis_client" | ||||
| "code.gitea.io/gitea/modules/redis/redis_key" | "code.gitea.io/gitea/modules/redis/redis_key" | ||||
| "code.gitea.io/gitea/modules/redis/redis_lock" | "code.gitea.io/gitea/modules/redis/redis_lock" | ||||
| "time" | |||||
| ) | ) | ||||
| var accessTokenLock = redis_lock.NewDistributeLock(redis_key.AccessTokenLockKey()) | var accessTokenLock = redis_lock.NewDistributeLock(redis_key.AccessTokenLockKey()) | ||||
| @@ -24,6 +24,7 @@ const ( | |||||
| CodeMountPath = "/code" | CodeMountPath = "/code" | ||||
| DataSetMountPath = "/dataset" | DataSetMountPath = "/dataset" | ||||
| ModelMountPath = "/model" | ModelMountPath = "/model" | ||||
| PretrainModelMountPath = "/pretrainmodel" | |||||
| LogFile = "log.txt" | LogFile = "log.txt" | ||||
| BenchMarkMountPath = "/benchmark" | BenchMarkMountPath = "/benchmark" | ||||
| BenchMarkResourceID = 1 | BenchMarkResourceID = 1 | ||||
| @@ -77,6 +78,8 @@ type GenerateCloudBrainTaskReq struct { | |||||
| ModelVersion string | ModelVersion string | ||||
| CkptName string | CkptName string | ||||
| LabelName string | LabelName string | ||||
| PreTrainModelPath string | |||||
| PreTrainModelUrl string | |||||
| Spec *models.Specification | Spec *models.Specification | ||||
| } | } | ||||
| @@ -276,6 +279,16 @@ func GenerateTask(req GenerateCloudBrainTaskReq) error { | |||||
| }, | }, | ||||
| } | } | ||||
| if req.PreTrainModelUrl != "" { //预训练 | |||||
| volumes = append(volumes, models.Volume{ | |||||
| HostPath: models.StHostPath{ | |||||
| Path: req.PreTrainModelPath, | |||||
| MountPath: PretrainModelMountPath, | |||||
| ReadOnly: true, | |||||
| }, | |||||
| }) | |||||
| } | |||||
| if len(req.DatasetInfos) == 1 { | if len(req.DatasetInfos) == 1 { | ||||
| volumes = append(volumes, models.Volume{ | volumes = append(volumes, models.Volume{ | ||||
| HostPath: models.StHostPath{ | HostPath: models.StHostPath{ | ||||
| @@ -359,6 +372,7 @@ func GenerateTask(req GenerateCloudBrainTaskReq) error { | |||||
| CkptName: req.CkptName, | CkptName: req.CkptName, | ||||
| ResultUrl: req.ResultPath, | ResultUrl: req.ResultPath, | ||||
| LabelName: req.LabelName, | LabelName: req.LabelName, | ||||
| PreTrainModelUrl: req.PreTrainModelUrl, | |||||
| CreatedUnix: createTime, | CreatedUnix: createTime, | ||||
| UpdatedUnix: createTime, | UpdatedUnix: createTime, | ||||
| CommitID: req.CommitID, | CommitID: req.CommitID, | ||||
| @@ -145,7 +145,6 @@ sendjob: | |||||
| if jobResult.Code != Success { | if jobResult.Code != Success { | ||||
| return &jobResult, fmt.Errorf("jobResult err: %s", res.String()) | return &jobResult, fmt.Errorf("jobResult err: %s", res.String()) | ||||
| } | } | ||||
| return &jobResult, nil | return &jobResult, nil | ||||
| } | } | ||||
| @@ -22,9 +22,6 @@ const ( | |||||
| GpuWorkDir = "/tmp/" | GpuWorkDir = "/tmp/" | ||||
| NpuWorkDir = "/cache/" | NpuWorkDir = "/cache/" | ||||
| CommandPrepareScript = ";mkdir -p output;mkdir -p code;mkdir -p dataset;echo \"start loading script\";wget -q https://git.openi.org.cn/OpenIOSSG/script_for_grampus/archive/master.zip;" + | |||||
| "echo \"finish loading script\";unzip -q master.zip;cd script_for_grampus;chmod 777 downloader_for_obs uploader_for_npu downloader_for_minio uploader_for_gpu;" | |||||
| CodeArchiveName = "master.zip" | CodeArchiveName = "master.zip" | ||||
| ) | ) | ||||
| @@ -34,6 +31,9 @@ var ( | |||||
| ImageInfos *setting.StImageInfosModelArts | ImageInfos *setting.StImageInfosModelArts | ||||
| SpecialPools *models.SpecialPools | SpecialPools *models.SpecialPools | ||||
| CommandPrepareScript = ";mkdir -p output;mkdir -p code;mkdir -p dataset;mkdir -p pretrainmodel;echo \"start loading script\";wget -q https://git.openi.org.cn/OpenIOSSG/%s/archive/master.zip;" + | |||||
| "echo \"finish loading script\";unzip -q master.zip;cd %s;chmod 777 downloader_for_obs uploader_for_npu downloader_for_minio uploader_for_gpu;" | |||||
| ) | ) | ||||
| type GenerateTrainJobReq struct { | type GenerateTrainJobReq struct { | ||||
| @@ -62,8 +62,16 @@ type GenerateTrainJobReq struct { | |||||
| TotalVersionCount int | TotalVersionCount int | ||||
| ComputeResource string | ComputeResource string | ||||
| ProcessType string | ProcessType string | ||||
| DatasetName string | |||||
| DatasetNames string | |||||
| DatasetInfos map[string]models.DatasetInfo | |||||
| Params string | Params string | ||||
| ModelName string | |||||
| LabelName string | |||||
| CkptName string | |||||
| ModelVersion string | |||||
| PreTrainModelPath string | |||||
| PreTrainModelUrl string | |||||
| Spec *models.Specification | Spec *models.Specification | ||||
| } | } | ||||
| @@ -72,6 +80,8 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error | |||||
| centerID, centerName := getCentersParamter(ctx, req) | centerID, centerName := getCentersParamter(ctx, req) | ||||
| log.Info("grampus Command:" + req.Command) | |||||
| jobResult, err := createJob(models.CreateGrampusJobRequest{ | jobResult, err := createJob(models.CreateGrampusJobRequest{ | ||||
| Name: req.JobName, | Name: req.JobName, | ||||
| Tasks: []models.GrampusTasks{ | Tasks: []models.GrampusTasks{ | ||||
| @@ -103,7 +113,7 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error | |||||
| JobType: string(models.JobTypeTrain), | JobType: string(models.JobTypeTrain), | ||||
| Type: models.TypeC2Net, | Type: models.TypeC2Net, | ||||
| Uuid: req.Uuid, | Uuid: req.Uuid, | ||||
| DatasetName: req.DatasetName, | |||||
| DatasetName: req.DatasetNames, | |||||
| CommitID: req.CommitID, | CommitID: req.CommitID, | ||||
| IsLatestVersion: req.IsLatestVersion, | IsLatestVersion: req.IsLatestVersion, | ||||
| ComputeResource: req.ComputeResource, | ComputeResource: req.ComputeResource, | ||||
| @@ -121,6 +131,11 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error | |||||
| CreatedUnix: createTime, | CreatedUnix: createTime, | ||||
| UpdatedUnix: createTime, | UpdatedUnix: createTime, | ||||
| Spec: req.Spec, | Spec: req.Spec, | ||||
| ModelName: req.ModelName, | |||||
| ModelVersion: req.ModelVersion, | |||||
| LabelName: req.LabelName, | |||||
| PreTrainModelUrl: req.PreTrainModelUrl, | |||||
| CkptName: req.CkptName, | |||||
| }) | }) | ||||
| if err != nil { | if err != nil { | ||||
| @@ -104,6 +104,11 @@ type GenerateTrainJobReq struct { | |||||
| UserCommand string | UserCommand string | ||||
| DatasetName string | DatasetName string | ||||
| Spec *models.Specification | Spec *models.Specification | ||||
| ModelName string | |||||
| LabelName string | |||||
| CkptName string | |||||
| ModelVersion string | |||||
| PreTrainModelUrl string | |||||
| } | } | ||||
| type GenerateInferenceJobReq struct { | type GenerateInferenceJobReq struct { | ||||
| @@ -440,6 +445,11 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error | |||||
| CreatedUnix: createTime, | CreatedUnix: createTime, | ||||
| UpdatedUnix: createTime, | UpdatedUnix: createTime, | ||||
| Spec: req.Spec, | Spec: req.Spec, | ||||
| ModelName: req.ModelName, | |||||
| ModelVersion: req.ModelVersion, | |||||
| LabelName: req.LabelName, | |||||
| PreTrainModelUrl: req.PreTrainModelUrl, | |||||
| CkptName: req.CkptName, | |||||
| }) | }) | ||||
| if createErr != nil { | if createErr != nil { | ||||
| @@ -589,6 +599,11 @@ func GenerateTrainJobVersion(ctx *context.Context, req *GenerateTrainJobReq, job | |||||
| CreatedUnix: createTime, | CreatedUnix: createTime, | ||||
| UpdatedUnix: createTime, | UpdatedUnix: createTime, | ||||
| Spec: req.Spec, | Spec: req.Spec, | ||||
| ModelName: req.ModelName, | |||||
| ModelVersion: req.ModelVersion, | |||||
| LabelName: req.LabelName, | |||||
| PreTrainModelUrl: req.PreTrainModelUrl, | |||||
| CkptName: req.CkptName, | |||||
| }) | }) | ||||
| if createErr != nil { | if createErr != nil { | ||||
| log.Error("CreateCloudbrain(%s) failed:%v", req.JobName, createErr.Error()) | log.Error("CreateCloudbrain(%s) failed:%v", req.JobName, createErr.Error()) | ||||
| @@ -0,0 +1,7 @@ | |||||
| package redis_key | |||||
| const CLOUDBRAIN_PREFIX = "cloudbrain" | |||||
| func CloudbrainBindingJobNameKey(repoId string, jobType string, jobName string) string { | |||||
| return KeyJoin(CLOUDBRAIN_PREFIX, repoId, jobType, jobName, "redis_key") | |||||
| } | |||||
| @@ -1,8 +1,9 @@ | |||||
| package redis_lock | package redis_lock | ||||
| import ( | import ( | ||||
| "code.gitea.io/gitea/modules/redis/redis_client" | |||||
| "time" | "time" | ||||
| "code.gitea.io/gitea/modules/redis/redis_client" | |||||
| ) | ) | ||||
| type DistributeLock struct { | type DistributeLock struct { | ||||
| @@ -587,12 +587,13 @@ var ( | |||||
| //grampus config | //grampus config | ||||
| Grampus = struct { | Grampus = struct { | ||||
| Env string | |||||
| Host string | |||||
| UserName string | |||||
| Password string | |||||
| SpecialPools string | |||||
| C2NetSequence string | |||||
| Env string | |||||
| Host string | |||||
| UserName string | |||||
| Password string | |||||
| SpecialPools string | |||||
| C2NetSequence string | |||||
| SyncScriptProject string | |||||
| }{} | }{} | ||||
| C2NetInfos *C2NetSqInfos | C2NetInfos *C2NetSqInfos | ||||
| @@ -1576,6 +1577,8 @@ func getGrampusConfig() { | |||||
| log.Error("Unmarshal(C2NetSequence) failed:%v", err) | log.Error("Unmarshal(C2NetSequence) failed:%v", err) | ||||
| } | } | ||||
| } | } | ||||
| Grampus.SyncScriptProject = sec.Key("SYNC_SCRIPT_PROJECT").MustString("script_for_grampus") | |||||
| } | } | ||||
| func SetRadarMapConfig() { | func SetRadarMapConfig() { | ||||
| @@ -1101,6 +1101,7 @@ cloudbrain_operate = Operate | |||||
| cloudbrain_status_createtime = Status/Createtime | cloudbrain_status_createtime = Status/Createtime | ||||
| cloudbrain_status_runtime = Running Time | cloudbrain_status_runtime = Running Time | ||||
| cloudbrain_jobname_err=Name must start with a lowercase letter or number,can include lowercase letter,number,_ and -,can not end with _, and can be up to 36 characters long. | cloudbrain_jobname_err=Name must start with a lowercase letter or number,can include lowercase letter,number,_ and -,can not end with _, and can be up to 36 characters long. | ||||
| cloudbrain_samejob_err=A task with the same name has been created, the system is processing it, please wait a minute. | |||||
| cloudbrain_bootfile_err=The bootfile does not exist in the repository | cloudbrain_bootfile_err=The bootfile does not exist in the repository | ||||
| cloudbrain_query_fail=Failed to query cloudbrain information. | cloudbrain_query_fail=Failed to query cloudbrain information. | ||||
| cloudbrain.mirror_tag = Mirror Tag | cloudbrain.mirror_tag = Mirror Tag | ||||
| @@ -1105,6 +1105,7 @@ cloudbrain_operate=操作 | |||||
| cloudbrain_status_createtime=状态/创建时间 | cloudbrain_status_createtime=状态/创建时间 | ||||
| cloudbrain_status_runtime = 运行时长 | cloudbrain_status_runtime = 运行时长 | ||||
| cloudbrain_jobname_err=只能以小写字母或数字开头且只包含小写字母、数字、_和-,不能以_结尾,最长36个字符。 | cloudbrain_jobname_err=只能以小写字母或数字开头且只包含小写字母、数字、_和-,不能以_结尾,最长36个字符。 | ||||
| cloudbrain_samejob_err=同名任务已经被创建,系统处理中,请您稍候。 | |||||
| cloudbrain_bootfile_err=仓库中不存在启动文件 | cloudbrain_bootfile_err=仓库中不存在启动文件 | ||||
| cloudbrain_query_fail=查询云脑任务失败。 | cloudbrain_query_fail=查询云脑任务失败。 | ||||
| cloudbrain.mirror_tag = 镜像标签 | cloudbrain.mirror_tag = 镜像标签 | ||||
| @@ -3256,6 +3257,8 @@ load_code_failed=代码加载失败,请确认选择了正确的分支。 | |||||
| error.dataset_select = 数据集选择错误:数量超过限制或者有同名数据集 | error.dataset_select = 数据集选择错误:数量超过限制或者有同名数据集 | ||||
| new_train_gpu_tooltips =训练脚本存储在<strong style="color:#010101">%s</strong>中,数据集存储在<strong style="color:#010101">%s</strong>中,训练输出请存储在<strong style="color:#010101">%s</strong>中以供后续下载。 | |||||
| new_infer_gpu_tooltips = 数据集存储在<strong style="color:#010101">%s</strong>中,模型文件存储在<strong style="color:#010101">%s</strong>中,推理输出请存储在<strong style="color:#010101">%s</strong>中以供后续下载。 | |||||
| [points] | [points] | ||||
| points = 积分 | points = 积分 | ||||
| @@ -3267,5 +3270,4 @@ expected_time = ,预计可用 | |||||
| points_acquisition_instructions = 积分获取说明 | points_acquisition_instructions = 积分获取说明 | ||||
| insufficient_points_balance = 积分余额不足 | insufficient_points_balance = 积分余额不足 | ||||
| new_train_gpu_tooltips =训练脚本存储在<strong style="color:#010101">%s</strong>中,数据集存储在<strong style="color:#010101">%s</strong>中,训练输出请存储在<strong style="color:#010101">%s</strong>中以供后续下载。 | |||||
| new_infer_gpu_tooltips = 数据集存储在<strong style="color:#010101">%s</strong>中,模型文件存储在<strong style="color:#010101">%s</strong>中,推理输出请存储在<strong style="color:#010101">%s</strong>中以供后续下载。 | |||||
| @@ -733,6 +733,7 @@ func GetCloudbrainsDetailData(ctx *context.Context) { | |||||
| ctx.ServerError("Get job failed:", err) | ctx.ServerError("Get job failed:", err) | ||||
| return | return | ||||
| } | } | ||||
| models.LoadSpecs4CloudbrainInfo(ciTasks) | |||||
| nilTime := time.Time{} | nilTime := time.Time{} | ||||
| tasks := []models.TaskDetail{} | tasks := []models.TaskDetail{} | ||||
| for i, task := range ciTasks { | for i, task := range ciTasks { | ||||
| @@ -769,6 +770,7 @@ func GetCloudbrainsDetailData(ctx *context.Context) { | |||||
| } else { | } else { | ||||
| taskDetail.IsDelete = false | taskDetail.IsDelete = false | ||||
| } | } | ||||
| taskDetail.Spec = ciTasks[i].Spec | |||||
| tasks = append(tasks, taskDetail) | tasks = append(tasks, taskDetail) | ||||
| } | } | ||||
| @@ -2,8 +2,6 @@ package repo | |||||
| import ( | import ( | ||||
| "bufio" | "bufio" | ||||
| "code.gitea.io/gitea/services/cloudbrain/resource" | |||||
| "code.gitea.io/gitea/services/reward/point/account" | |||||
| "encoding/json" | "encoding/json" | ||||
| "errors" | "errors" | ||||
| "fmt" | "fmt" | ||||
| @@ -17,6 +15,9 @@ import ( | |||||
| "time" | "time" | ||||
| "unicode/utf8" | "unicode/utf8" | ||||
| "code.gitea.io/gitea/services/cloudbrain/resource" | |||||
| "code.gitea.io/gitea/services/reward/point/account" | |||||
| "code.gitea.io/gitea/modules/notification" | "code.gitea.io/gitea/modules/notification" | ||||
| "code.gitea.io/gitea/modules/grampus" | "code.gitea.io/gitea/modules/grampus" | ||||
| @@ -32,6 +33,8 @@ import ( | |||||
| "code.gitea.io/gitea/modules/git" | "code.gitea.io/gitea/modules/git" | ||||
| "code.gitea.io/gitea/modules/log" | "code.gitea.io/gitea/modules/log" | ||||
| "code.gitea.io/gitea/modules/modelarts" | "code.gitea.io/gitea/modules/modelarts" | ||||
| "code.gitea.io/gitea/modules/redis/redis_key" | |||||
| "code.gitea.io/gitea/modules/redis/redis_lock" | |||||
| "code.gitea.io/gitea/modules/setting" | "code.gitea.io/gitea/modules/setting" | ||||
| "code.gitea.io/gitea/modules/storage" | "code.gitea.io/gitea/modules/storage" | ||||
| "code.gitea.io/gitea/modules/util" | "code.gitea.io/gitea/modules/util" | ||||
| @@ -138,6 +141,35 @@ func cloudBrainNewDataPrepare(ctx *context.Context) error { | |||||
| ctx.Data["benchmarkMode"] = ctx.Query("benchmarkMode") | ctx.Data["benchmarkMode"] = ctx.Query("benchmarkMode") | ||||
| if ctx.Cloudbrain != nil { | |||||
| ctx.Data["branch_name"] = ctx.Cloudbrain.BranchName | |||||
| ctx.Data["image"] = ctx.Cloudbrain.Image | |||||
| ctx.Data["image_id"] = ctx.Cloudbrain.ImageID | |||||
| ctx.Data["boot_file"] = ctx.Cloudbrain.BootFile | |||||
| ctx.Data["description"] = ctx.Cloudbrain.Description | |||||
| spec, _ := resource.GetCloudbrainSpec(ctx.Cloudbrain.ID) | |||||
| if spec != nil { | |||||
| ctx.Data["spec_id"] = spec.ID | |||||
| } | |||||
| ctx.Data["run_para_list"] = ctx.Cloudbrain.Parameters | |||||
| ctx.Data["model_name"] = ctx.Cloudbrain.ModelName | |||||
| ctx.Data["label_name"] = ctx.Cloudbrain.LabelName | |||||
| ctx.Data["ckpt_name"] = ctx.Cloudbrain.CkptName | |||||
| ctx.Data["model_version"] = ctx.Cloudbrain.ModelVersion | |||||
| ctx.Data["pre_train_model_url"] = ctx.Cloudbrain.PreTrainModelUrl | |||||
| ctx.Data["compute_resource"] = ctx.Cloudbrain.ComputeResource | |||||
| ctx.Data["attachment"] = ctx.Cloudbrain.Uuid | |||||
| ctx.Data["cluster_type"] = models.OpenICluster | |||||
| _, _, datasetNames, _, err := getDatasUrlListByUUIDS(ctx.Cloudbrain.Uuid) | |||||
| if err != nil { | |||||
| log.Info("query dataset error," + err.Error()) | |||||
| ctx.Data["dataset_name"] = "" | |||||
| } else { | |||||
| ctx.Data["dataset_name"] = datasetNames | |||||
| } | |||||
| } | |||||
| return nil | return nil | ||||
| } | } | ||||
| @@ -184,8 +216,12 @@ func CloudBrainNew(ctx *context.Context) { | |||||
| ctx.Data["PageIsGPUDebug"] = true | ctx.Data["PageIsGPUDebug"] = true | ||||
| ctx.HTML(200, tplCloudBrainNew) | ctx.HTML(200, tplCloudBrainNew) | ||||
| } | } | ||||
| func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { | func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { | ||||
| ctx.Data["IsCreate"] = true | |||||
| cloudBrainCreate(ctx, form) | |||||
| } | |||||
| func cloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { | |||||
| ctx.Data["PageIsCloudBrain"] = true | ctx.Data["PageIsCloudBrain"] = true | ||||
| displayJobName := form.DisplayJobName | displayJobName := form.DisplayJobName | ||||
| jobName := util.ConvertDisplayJobNameToJobName(displayJobName) | jobName := util.ConvertDisplayJobNameToJobName(displayJobName) | ||||
| @@ -202,6 +238,16 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { | |||||
| tpl = tplCloudBrainTrainJobNew | tpl = tplCloudBrainTrainJobNew | ||||
| } | } | ||||
| lock := redis_lock.NewDistributeLock(redis_key.CloudbrainBindingJobNameKey(fmt.Sprint(repo.ID), jobType, displayJobName)) | |||||
| isOk, err := lock.Lock(models.CloudbrainKeyDuration) | |||||
| if !isOk { | |||||
| log.Error("lock processed failed:%v", err, ctx.Data["MsgID"]) | |||||
| cloudBrainNewDataPrepare(ctx) | |||||
| ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_samejob_err"), tpl, &form) | |||||
| return | |||||
| } | |||||
| defer lock.UnLock() | |||||
| tasks, err := models.GetCloudbrainsByDisplayJobName(repo.ID, jobType, displayJobName) | tasks, err := models.GetCloudbrainsByDisplayJobName(repo.ID, jobType, displayJobName) | ||||
| if err == nil { | if err == nil { | ||||
| if len(tasks) != 0 { | if len(tasks) != 0 { | ||||
| @@ -336,13 +382,22 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { | |||||
| Spec: spec, | Spec: spec, | ||||
| } | } | ||||
| if form.ModelName != "" { //使用预训练模型训练 | |||||
| req.ModelName = form.ModelName | |||||
| req.LabelName = form.LabelName | |||||
| req.CkptName = form.CkptName | |||||
| req.ModelVersion = form.ModelVersion | |||||
| req.PreTrainModelPath = setting.Attachment.Minio.RealPath + form.PreTrainModelUrl | |||||
| req.PreTrainModelUrl = form.PreTrainModelUrl | |||||
| } | |||||
| err = cloudbrain.GenerateTask(req) | err = cloudbrain.GenerateTask(req) | ||||
| if err != nil { | if err != nil { | ||||
| cloudBrainNewDataPrepare(ctx) | cloudBrainNewDataPrepare(ctx) | ||||
| ctx.RenderWithErr(err.Error(), tpl, &form) | ctx.RenderWithErr(err.Error(), tpl, &form) | ||||
| return | return | ||||
| } | } | ||||
| if jobType == string(models.JobTypeTrain) { | if jobType == string(models.JobTypeTrain) { | ||||
| ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/train-job?listType=all") | ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/train-job?listType=all") | ||||
| } else { | } else { | ||||
| @@ -350,6 +405,11 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { | |||||
| } | } | ||||
| } | } | ||||
| func CloudBrainTrainJobVersionCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { | |||||
| ctx.Data["IsCreate"] = false | |||||
| cloudBrainCreate(ctx, form) | |||||
| } | |||||
| func loadCodeAndMakeModelPath(repo *models.Repository, codePath string, branchName string, jobName string, resultPath string) string { | func loadCodeAndMakeModelPath(repo *models.Repository, codePath string, branchName string, jobName string, resultPath string) string { | ||||
| err := downloadCode(repo, codePath, branchName) | err := downloadCode(repo, codePath, branchName) | ||||
| if err != nil { | if err != nil { | ||||
| @@ -386,10 +446,20 @@ func CloudBrainInferenceJobCreate(ctx *context.Context, form auth.CreateCloudBra | |||||
| bootFile := strings.TrimSpace(form.BootFile) | bootFile := strings.TrimSpace(form.BootFile) | ||||
| labelName := form.LabelName | labelName := form.LabelName | ||||
| repo := ctx.Repo.Repository | repo := ctx.Repo.Repository | ||||
| tpl := tplCloudBrainInferenceJobNew | |||||
| lock := redis_lock.NewDistributeLock(redis_key.CloudbrainBindingJobNameKey(fmt.Sprint(repo.ID), jobType, displayJobName)) | |||||
| isOk, err := lock.Lock(models.CloudbrainKeyDuration) | |||||
| if !isOk { | |||||
| log.Error("lock processed failed:%v", err, ctx.Data["MsgID"]) | |||||
| cloudBrainNewDataPrepare(ctx) | |||||
| ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_samejob_err"), tpl, &form) | |||||
| return | |||||
| } | |||||
| defer lock.UnLock() | |||||
| ckptUrl := setting.Attachment.Minio.RealPath + form.TrainUrl + form.CkptName | ckptUrl := setting.Attachment.Minio.RealPath + form.TrainUrl + form.CkptName | ||||
| log.Info("ckpt url:" + ckptUrl) | log.Info("ckpt url:" + ckptUrl) | ||||
| tpl := tplCloudBrainInferenceJobNew | |||||
| command, err := getInferenceJobCommand(form) | command, err := getInferenceJobCommand(form) | ||||
| if err != nil { | if err != nil { | ||||
| log.Error("getTrainJobCommand failed: %v", err) | log.Error("getTrainJobCommand failed: %v", err) | ||||
| @@ -1840,6 +1910,10 @@ func SyncCloudbrainStatus() { | |||||
| oldStatus := task.Status | oldStatus := task.Status | ||||
| task.Status = grampus.TransTrainJobStatus(result.JobInfo.Status) | task.Status = grampus.TransTrainJobStatus(result.JobInfo.Status) | ||||
| task.Duration = result.JobInfo.RunSec | task.Duration = result.JobInfo.RunSec | ||||
| if task.Duration < 0 { | |||||
| task.Duration = 0 | |||||
| } | |||||
| task.TrainJobDuration = models.ConvertDurationToStr(task.Duration) | task.TrainJobDuration = models.ConvertDurationToStr(task.Duration) | ||||
| if task.StartTime == 0 && result.JobInfo.StartedAt > 0 { | if task.StartTime == 0 && result.JobInfo.StartedAt > 0 { | ||||
| @@ -2234,12 +2308,21 @@ func BenchMarkAlgorithmCreate(ctx *context.Context, form auth.CreateCloudBrainFo | |||||
| codePath := setting.JobPath + jobName + cloudbrain.CodeMountPath | codePath := setting.JobPath + jobName + cloudbrain.CodeMountPath | ||||
| benchmarkTypeID := form.BenchmarkTypeID | benchmarkTypeID := form.BenchmarkTypeID | ||||
| benchmarkChildTypeID := form.BenchmarkChildTypeID | benchmarkChildTypeID := form.BenchmarkChildTypeID | ||||
| repo := ctx.Repo.Repository | |||||
| ctx.Data["description"] = form.Description | ctx.Data["description"] = form.Description | ||||
| ctx.Data["benchmarkTypeID"] = benchmarkTypeID | ctx.Data["benchmarkTypeID"] = benchmarkTypeID | ||||
| ctx.Data["benchmark_child_types_id_hidden"] = benchmarkChildTypeID | ctx.Data["benchmark_child_types_id_hidden"] = benchmarkChildTypeID | ||||
| repo := ctx.Repo.Repository | |||||
| lock := redis_lock.NewDistributeLock(redis_key.CloudbrainBindingJobNameKey(fmt.Sprint(repo.ID), form.JobType, displayJobName)) | |||||
| isOk, err := lock.Lock(models.CloudbrainKeyDuration) | |||||
| if !isOk { | |||||
| log.Error("lock processed failed:%v", err, ctx.Data["MsgID"]) | |||||
| cloudBrainNewDataPrepare(ctx) | |||||
| ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_samejob_err"), tplCloudBrainBenchmarkNew, &form) | |||||
| return | |||||
| } | |||||
| defer lock.UnLock() | |||||
| tasks, err := models.GetCloudbrainsByDisplayJobName(repo.ID, string(models.JobTypeBenchmark), displayJobName) | tasks, err := models.GetCloudbrainsByDisplayJobName(repo.ID, string(models.JobTypeBenchmark), displayJobName) | ||||
| if err == nil { | if err == nil { | ||||
| @@ -2421,6 +2504,16 @@ func ModelBenchmarkCreate(ctx *context.Context, form auth.CreateCloudBrainForm) | |||||
| tpl := tplCloudBrainBenchmarkNew | tpl := tplCloudBrainBenchmarkNew | ||||
| command := cloudbrain.GetCloudbrainDebugCommand() | command := cloudbrain.GetCloudbrainDebugCommand() | ||||
| lock := redis_lock.NewDistributeLock(redis_key.CloudbrainBindingJobNameKey(fmt.Sprint(repo.ID), jobType, displayJobName)) | |||||
| isOk, err := lock.Lock(models.CloudbrainKeyDuration) | |||||
| if !isOk { | |||||
| log.Error("lock processed failed:%v", err, ctx.Data["MsgID"]) | |||||
| cloudBrainNewDataPrepare(ctx) | |||||
| ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_samejob_err"), tpl, &form) | |||||
| return | |||||
| } | |||||
| defer lock.UnLock() | |||||
| tasks, err := models.GetCloudbrainsByDisplayJobName(repo.ID, jobType, displayJobName) | tasks, err := models.GetCloudbrainsByDisplayJobName(repo.ID, jobType, displayJobName) | ||||
| if err == nil { | if err == nil { | ||||
| if len(tasks) != 0 { | if len(tasks) != 0 { | ||||
| @@ -2581,6 +2674,15 @@ func BenchmarkDel(ctx *context.Context) { | |||||
| } | } | ||||
| func CloudBrainTrainJobNew(ctx *context.Context) { | func CloudBrainTrainJobNew(ctx *context.Context) { | ||||
| ctx.Data["IsCreate"] = true | |||||
| cloudBrainTrainJobCreate(ctx) | |||||
| } | |||||
| func CloudBrainTrainJobVersionNew(ctx *context.Context) { | |||||
| ctx.Data["IsCreate"] = false | |||||
| cloudBrainTrainJobCreate(ctx) | |||||
| } | |||||
| func cloudBrainTrainJobCreate(ctx *context.Context) { | |||||
| err := cloudBrainNewDataPrepare(ctx) | err := cloudBrainNewDataPrepare(ctx) | ||||
| if err != nil { | if err != nil { | ||||
| ctx.ServerError("get new train-job info failed", err) | ctx.ServerError("get new train-job info failed", err) | ||||
| @@ -2670,6 +2772,9 @@ func getTrainJobCommand(form auth.CreateCloudBrainForm) (string, error) { | |||||
| param += " --" + parameter.Label + "=" + parameter.Value | param += " --" + parameter.Label + "=" + parameter.Value | ||||
| } | } | ||||
| } | } | ||||
| if form.CkptName != "" { | |||||
| param += " --pretrainmodelname" + "=" + form.CkptName | |||||
| } | |||||
| command += "python /code/" + bootFile + param + " > " + cloudbrain.ModelMountPath + "/" + form.DisplayJobName + "-" + cloudbrain.LogFile | command += "python /code/" + bootFile + param + " > " + cloudbrain.ModelMountPath + "/" + form.DisplayJobName + "-" + cloudbrain.LogFile | ||||
| @@ -1,8 +1,6 @@ | |||||
| package repo | package repo | ||||
| import ( | import ( | ||||
| "code.gitea.io/gitea/services/cloudbrain/resource" | |||||
| "code.gitea.io/gitea/services/reward/point/account" | |||||
| "encoding/json" | "encoding/json" | ||||
| "errors" | "errors" | ||||
| "fmt" | "fmt" | ||||
| @@ -14,11 +12,18 @@ import ( | |||||
| "strings" | "strings" | ||||
| "time" | "time" | ||||
| "code.gitea.io/gitea/services/cloudbrain/resource" | |||||
| "code.gitea.io/gitea/services/reward/point/account" | |||||
| "code.gitea.io/gitea/modules/auth" | "code.gitea.io/gitea/modules/auth" | ||||
| "code.gitea.io/gitea/modules/git" | "code.gitea.io/gitea/modules/git" | ||||
| "code.gitea.io/gitea/modules/grampus" | "code.gitea.io/gitea/modules/grampus" | ||||
| "code.gitea.io/gitea/modules/modelarts" | "code.gitea.io/gitea/modules/modelarts" | ||||
| "code.gitea.io/gitea/modules/notification" | "code.gitea.io/gitea/modules/notification" | ||||
| "code.gitea.io/gitea/modules/redis/redis_key" | |||||
| "code.gitea.io/gitea/modules/redis/redis_lock" | |||||
| "code.gitea.io/gitea/modules/timeutil" | "code.gitea.io/gitea/modules/timeutil" | ||||
| "code.gitea.io/gitea/modules/util" | "code.gitea.io/gitea/modules/util" | ||||
| "github.com/unknwon/com" | "github.com/unknwon/com" | ||||
| @@ -42,7 +47,7 @@ const ( | |||||
| ) | ) | ||||
| func GrampusTrainJobGPUNew(ctx *context.Context) { | func GrampusTrainJobGPUNew(ctx *context.Context) { | ||||
| ctx.Data["datasetType"] = models.TypeCloudBrainOne | |||||
| ctx.Data["IsCreate"] = true | |||||
| err := grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) | err := grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) | ||||
| if err != nil { | if err != nil { | ||||
| ctx.ServerError("get new train-job info failed", err) | ctx.ServerError("get new train-job info failed", err) | ||||
| @@ -53,7 +58,7 @@ func GrampusTrainJobGPUNew(ctx *context.Context) { | |||||
| } | } | ||||
| func GrampusTrainJobNPUNew(ctx *context.Context) { | func GrampusTrainJobNPUNew(ctx *context.Context) { | ||||
| ctx.Data["datasetType"] = models.TypeCloudBrainTwo | |||||
| ctx.Data["IsCreate"] = true | |||||
| err := grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) | err := grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) | ||||
| if err != nil { | if err != nil { | ||||
| ctx.ServerError("get new train-job info failed", err) | ctx.ServerError("get new train-job info failed", err) | ||||
| @@ -135,9 +140,56 @@ func grampusTrainJobNewDataPrepare(ctx *context.Context, processType string) err | |||||
| ctx.Data["WaitCount"] = waitCount | ctx.Data["WaitCount"] = waitCount | ||||
| } | } | ||||
| if ctx.Cloudbrain != nil { | |||||
| ctx.Data["attachment"] = ctx.Cloudbrain.Uuid | |||||
| ctx.Data["boot_file"] = ctx.Cloudbrain.BootFile | |||||
| ctx.Data["image_id"] = ctx.Cloudbrain.ImageID | |||||
| ctx.Data["run_para_list"] = ctx.Cloudbrain.Parameters | |||||
| ctx.Data["description"] = ctx.Cloudbrain.Description | |||||
| ctx.Data["branch_name"] = ctx.Cloudbrain.BranchName | |||||
| ctx.Data["engine_name"] = ctx.Cloudbrain.EngineName | |||||
| ctx.Data["WorkServerNumber"] = ctx.Cloudbrain.WorkServerNumber | |||||
| if ctx.Cloudbrain.Image != "" { | |||||
| ctx.Data["image"] = ctx.Cloudbrain.Image | |||||
| } else { | |||||
| ctx.Data["image"] = ctx.Cloudbrain.EngineName | |||||
| } | |||||
| ctx.Data["dataset_name"] = ctx.Cloudbrain.DatasetName | |||||
| ctx.Data["model_name"] = ctx.Cloudbrain.ModelName | |||||
| ctx.Data["model_version"] = ctx.Cloudbrain.ModelVersion | |||||
| ctx.Data["ckpt_name"] = ctx.Cloudbrain.CkptName | |||||
| ctx.Data["label_names"] = ctx.Cloudbrain.LabelName | |||||
| ctx.Data["PreTrainModelUrl"] = ctx.Cloudbrain.PreTrainModelUrl | |||||
| spec, _ := resource.GetCloudbrainSpec(ctx.Cloudbrain.ID) | |||||
| if spec != nil { | |||||
| ctx.Data["spec_id"] = spec.ID | |||||
| } | |||||
| } | |||||
| return nil | return nil | ||||
| } | } | ||||
| func GrampusTrainJobVersionNew(ctx *context.Context) { | |||||
| task := ctx.Cloudbrain | |||||
| ctx.Data["IsCreate"] = false | |||||
| if task.ComputeResource == models.GPUResource { | |||||
| err := grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) | |||||
| if err != nil { | |||||
| ctx.ServerError("get new train-job version info failed", err) | |||||
| return | |||||
| } | |||||
| ctx.HTML(http.StatusOK, tplGrampusTrainJobGPUNew) | |||||
| } else if task.ComputeResource == models.NPUResource { | |||||
| err := grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) | |||||
| if err != nil { | |||||
| ctx.ServerError("get new train-job version info failed", err) | |||||
| return | |||||
| } | |||||
| ctx.HTML(200, tplGrampusTrainJobNPUNew) | |||||
| } | |||||
| } | |||||
| func prepareGrampusTrainSpecs(ctx *context.Context, computeResource string) { | func prepareGrampusTrainSpecs(ctx *context.Context, computeResource string) { | ||||
| noteBookSpecs, _ := resource.FindAvailableSpecs(ctx.User.ID, models.FindSpecsOptions{ | noteBookSpecs, _ := resource.FindAvailableSpecs(ctx.User.ID, models.FindSpecsOptions{ | ||||
| JobType: models.JobTypeTrain, | JobType: models.JobTypeTrain, | ||||
| @@ -202,6 +254,7 @@ func grampusParamCheckCreateTrainJob(form auth.CreateGrampusTrainJobForm) error | |||||
| } | } | ||||
| func GrampusTrainJobGpuCreate(ctx *context.Context, form auth.CreateGrampusTrainJobForm) { | func GrampusTrainJobGpuCreate(ctx *context.Context, form auth.CreateGrampusTrainJobForm) { | ||||
| ctx.Data["IsCreate"] = true | |||||
| displayJobName := form.DisplayJobName | displayJobName := form.DisplayJobName | ||||
| jobName := util.ConvertDisplayJobNameToJobName(displayJobName) | jobName := util.ConvertDisplayJobNameToJobName(displayJobName) | ||||
| uuid := form.Attachment | uuid := form.Attachment | ||||
| @@ -211,28 +264,31 @@ func GrampusTrainJobGpuCreate(ctx *context.Context, form auth.CreateGrampusTrain | |||||
| repo := ctx.Repo.Repository | repo := ctx.Repo.Repository | ||||
| codeLocalPath := setting.JobPath + jobName + cloudbrain.CodeMountPath + "/" | codeLocalPath := setting.JobPath + jobName + cloudbrain.CodeMountPath + "/" | ||||
| codeMinioPath := setting.CBCodePathPrefix + jobName + cloudbrain.CodeMountPath + "/" | codeMinioPath := setting.CBCodePathPrefix + jobName + cloudbrain.CodeMountPath + "/" | ||||
| dataMinioPath := setting.Attachment.Minio.BasePath + path.Join(uuid[0:1], uuid[1:2]) + "/" + uuid | |||||
| branchName := form.BranchName | branchName := form.BranchName | ||||
| image := strings.TrimSpace(form.Image) | image := strings.TrimSpace(form.Image) | ||||
| tpl := tplGrampusTrainJobGPUNew | |||||
| if !jobNamePattern.MatchString(displayJobName) { | |||||
| lock := redis_lock.NewDistributeLock(redis_key.CloudbrainBindingJobNameKey(fmt.Sprint(repo.ID), string(models.JobTypeTrain), displayJobName)) | |||||
| isOk, err := lock.Lock(models.CloudbrainKeyDuration) | |||||
| if !isOk { | |||||
| log.Error("lock processed failed:%v", err, ctx.Data["MsgID"]) | |||||
| grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) | grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) | ||||
| ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_jobname_err"), tplGrampusTrainJobGPUNew, &form) | |||||
| ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_samejob_err"), tplGrampusTrainJobGPUNew, &form) | |||||
| return | return | ||||
| } | } | ||||
| defer lock.UnLock() | |||||
| bootFileExist, err := ctx.Repo.FileExists(bootFile, branchName) | |||||
| if err != nil || !bootFileExist { | |||||
| log.Error("Get bootfile error:", err, ctx.Data["MsgID"]) | |||||
| if !jobNamePattern.MatchString(displayJobName) { | |||||
| grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) | grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) | ||||
| ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_bootfile_err"), tplGrampusTrainJobGPUNew, &form) | |||||
| ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_jobname_err"), tpl, &form) | |||||
| return | return | ||||
| } | } | ||||
| errStr := checkSpecialPool(ctx, "GPU") | |||||
| if errStr != "" { | |||||
| bootFileExist, err := ctx.Repo.FileExists(bootFile, branchName) | |||||
| if err != nil || !bootFileExist { | |||||
| log.Error("Get bootfile error:", err, ctx.Data["MsgID"]) | |||||
| grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) | grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) | ||||
| ctx.RenderWithErr(errStr, tplGrampusTrainJobGPUNew, &form) | |||||
| ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_bootfile_err"), tpl, &form) | |||||
| return | return | ||||
| } | } | ||||
| @@ -241,13 +297,13 @@ func GrampusTrainJobGpuCreate(ctx *context.Context, form auth.CreateGrampusTrain | |||||
| if err != nil { | if err != nil { | ||||
| log.Error("GetGrampusCountByUserID failed:%v", err, ctx.Data["MsgID"]) | log.Error("GetGrampusCountByUserID failed:%v", err, ctx.Data["MsgID"]) | ||||
| grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) | grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) | ||||
| ctx.RenderWithErr("system error", tplGrampusTrainJobGPUNew, &form) | |||||
| ctx.RenderWithErr("system error", tpl, &form) | |||||
| return | return | ||||
| } else { | } else { | ||||
| if count >= 1 { | if count >= 1 { | ||||
| log.Error("the user already has running or waiting task", ctx.Data["MsgID"]) | log.Error("the user already has running or waiting task", ctx.Data["MsgID"]) | ||||
| grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) | grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) | ||||
| ctx.RenderWithErr("you have already a running or waiting task, can not create more", tplGrampusTrainJobGPUNew, &form) | |||||
| ctx.RenderWithErr("you have already a running or waiting task, can not create more", tpl, &form) | |||||
| return | return | ||||
| } | } | ||||
| } | } | ||||
| @@ -256,7 +312,7 @@ func GrampusTrainJobGpuCreate(ctx *context.Context, form auth.CreateGrampusTrain | |||||
| if err := grampusParamCheckCreateTrainJob(form); err != nil { | if err := grampusParamCheckCreateTrainJob(form); err != nil { | ||||
| log.Error("paramCheckCreateTrainJob failed:(%v)", err, ctx.Data["MsgID"]) | log.Error("paramCheckCreateTrainJob failed:(%v)", err, ctx.Data["MsgID"]) | ||||
| grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) | grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) | ||||
| ctx.RenderWithErr(err.Error(), tplGrampusTrainJobGPUNew, &form) | |||||
| ctx.RenderWithErr(err.Error(), tpl, &form) | |||||
| return | return | ||||
| } | } | ||||
| @@ -266,14 +322,14 @@ func GrampusTrainJobGpuCreate(ctx *context.Context, form auth.CreateGrampusTrain | |||||
| if len(tasks) != 0 { | if len(tasks) != 0 { | ||||
| log.Error("the job name did already exist", ctx.Data["MsgID"]) | log.Error("the job name did already exist", ctx.Data["MsgID"]) | ||||
| grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) | grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) | ||||
| ctx.RenderWithErr("the job name did already exist", tplGrampusTrainJobGPUNew, &form) | |||||
| ctx.RenderWithErr("the job name did already exist", tpl, &form) | |||||
| return | return | ||||
| } | } | ||||
| } else { | } else { | ||||
| if !models.IsErrJobNotExist(err) { | if !models.IsErrJobNotExist(err) { | ||||
| log.Error("system error, %v", err, ctx.Data["MsgID"]) | log.Error("system error, %v", err, ctx.Data["MsgID"]) | ||||
| grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) | grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) | ||||
| ctx.RenderWithErr("system error", tplGrampusTrainJobGPUNew, &form) | |||||
| ctx.RenderWithErr("system error", tpl, &form) | |||||
| return | return | ||||
| } | } | ||||
| } | } | ||||
| @@ -286,7 +342,7 @@ func GrampusTrainJobGpuCreate(ctx *context.Context, form auth.CreateGrampusTrain | |||||
| }) | }) | ||||
| if err != nil || spec == nil { | if err != nil || spec == nil { | ||||
| grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) | grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) | ||||
| ctx.RenderWithErr("Resource specification not available", tplGrampusTrainJobGPUNew, &form) | |||||
| ctx.RenderWithErr("Resource specification not available", tpl, &form) | |||||
| return | return | ||||
| } | } | ||||
| @@ -298,11 +354,12 @@ func GrampusTrainJobGpuCreate(ctx *context.Context, form auth.CreateGrampusTrain | |||||
| } | } | ||||
| //check dataset | //check dataset | ||||
| attachment, err := models.GetAttachmentByUUID(uuid) | |||||
| datasetInfos, datasetNames, err := models.GetDatasetInfo(uuid, models.GPU) | |||||
| if err != nil { | if err != nil { | ||||
| log.Error("GetAttachmentByUUID failed:", err.Error(), ctx.Data["MsgID"]) | |||||
| log.Error("GetDatasetInfo failed: %v", err, ctx.Data["MsgID"]) | |||||
| grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) | grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) | ||||
| ctx.RenderWithErr("dataset is not exist", tplGrampusTrainJobGPUNew, &form) | |||||
| ctx.RenderWithErr(ctx.Tr("cloudbrain.error.dataset_select"), tpl, &form) | |||||
| return | return | ||||
| } | } | ||||
| @@ -315,7 +372,7 @@ func GrampusTrainJobGpuCreate(ctx *context.Context, form auth.CreateGrampusTrain | |||||
| if err := downloadZipCode(ctx, codeLocalPath, branchName); err != nil { | if err := downloadZipCode(ctx, codeLocalPath, branchName); err != nil { | ||||
| log.Error("downloadZipCode failed, server timed out: %s (%v)", repo.FullName(), err, ctx.Data["MsgID"]) | log.Error("downloadZipCode failed, server timed out: %s (%v)", repo.FullName(), err, ctx.Data["MsgID"]) | ||||
| grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) | grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) | ||||
| ctx.RenderWithErr(ctx.Tr("cloudbrain.load_code_failed"), tplGrampusTrainJobGPUNew, &form) | |||||
| ctx.RenderWithErr(ctx.Tr("cloudbrain.load_code_failed"), tpl, &form) | |||||
| return | return | ||||
| } | } | ||||
| @@ -324,7 +381,7 @@ func GrampusTrainJobGpuCreate(ctx *context.Context, form auth.CreateGrampusTrain | |||||
| if err := uploadCodeToMinio(codeLocalPath+"/", jobName, cloudbrain.CodeMountPath+"/"); err != nil { | if err := uploadCodeToMinio(codeLocalPath+"/", jobName, cloudbrain.CodeMountPath+"/"); err != nil { | ||||
| log.Error("Failed to uploadCodeToMinio: %s (%v)", repo.FullName(), err, ctx.Data["MsgID"]) | log.Error("Failed to uploadCodeToMinio: %s (%v)", repo.FullName(), err, ctx.Data["MsgID"]) | ||||
| grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) | grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) | ||||
| ctx.RenderWithErr(ctx.Tr("cloudbrain.load_code_failed"), tplGrampusTrainJobGPUNew, &form) | |||||
| ctx.RenderWithErr(ctx.Tr("cloudbrain.load_code_failed"), tpl, &form) | |||||
| return | return | ||||
| } | } | ||||
| @@ -332,7 +389,7 @@ func GrampusTrainJobGpuCreate(ctx *context.Context, form auth.CreateGrampusTrain | |||||
| if err := mkModelPath(modelPath); err != nil { | if err := mkModelPath(modelPath); err != nil { | ||||
| log.Error("Failed to mkModelPath: %s (%v)", repo.FullName(), err, ctx.Data["MsgID"]) | log.Error("Failed to mkModelPath: %s (%v)", repo.FullName(), err, ctx.Data["MsgID"]) | ||||
| grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) | grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) | ||||
| ctx.RenderWithErr(ctx.Tr("cloudbrain.load_code_failed"), tplGrampusTrainJobGPUNew, &form) | |||||
| ctx.RenderWithErr(ctx.Tr("cloudbrain.load_code_failed"), tpl, &form) | |||||
| return | return | ||||
| } | } | ||||
| @@ -340,52 +397,102 @@ func GrampusTrainJobGpuCreate(ctx *context.Context, form auth.CreateGrampusTrain | |||||
| if err := uploadCodeToMinio(modelPath, jobName, cloudbrain.ModelMountPath+"/"); err != nil { | if err := uploadCodeToMinio(modelPath, jobName, cloudbrain.ModelMountPath+"/"); err != nil { | ||||
| log.Error("Failed to uploadCodeToMinio: %s (%v)", repo.FullName(), err, ctx.Data["MsgID"]) | log.Error("Failed to uploadCodeToMinio: %s (%v)", repo.FullName(), err, ctx.Data["MsgID"]) | ||||
| grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) | grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) | ||||
| ctx.RenderWithErr(ctx.Tr("cloudbrain.load_code_failed"), tplGrampusTrainJobGPUNew, &form) | |||||
| ctx.RenderWithErr(ctx.Tr("cloudbrain.load_code_failed"), tpl, &form) | |||||
| return | return | ||||
| } | } | ||||
| var datasetRemotePath, allFileName string | |||||
| for _, datasetInfo := range datasetInfos { | |||||
| if datasetRemotePath == "" { | |||||
| datasetRemotePath = datasetInfo.DataLocalPath | |||||
| allFileName = datasetInfo.FullName | |||||
| } else { | |||||
| datasetRemotePath = datasetRemotePath + ";" + datasetInfo.DataLocalPath | |||||
| allFileName = allFileName + ";" + datasetInfo.FullName | |||||
| } | |||||
| } | |||||
| //prepare command | //prepare command | ||||
| command, err := generateCommand(repo.Name, grampus.ProcessorTypeGPU, codeMinioPath+cloudbrain.DefaultBranchName+".zip", dataMinioPath, bootFile, params, setting.CBCodePathPrefix+jobName+cloudbrain.ModelMountPath+"/", attachment.Name) | |||||
| preTrainModelPath := getPreTrainModelPath(form.PreTrainModelUrl, form.CkptName) | |||||
| command, err := generateCommand(repo.Name, grampus.ProcessorTypeGPU, codeMinioPath+cloudbrain.DefaultBranchName+".zip", datasetRemotePath, bootFile, params, setting.CBCodePathPrefix+jobName+cloudbrain.ModelMountPath+"/", allFileName, preTrainModelPath, form.CkptName) | |||||
| if err != nil { | if err != nil { | ||||
| log.Error("Failed to generateCommand: %s (%v)", displayJobName, err, ctx.Data["MsgID"]) | log.Error("Failed to generateCommand: %s (%v)", displayJobName, err, ctx.Data["MsgID"]) | ||||
| grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) | grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) | ||||
| ctx.RenderWithErr("Create task failed, internal error", tplGrampusTrainJobGPUNew, &form) | |||||
| ctx.RenderWithErr("Create task failed, internal error", tpl, &form) | |||||
| return | return | ||||
| } | } | ||||
| commitID, _ := ctx.Repo.GitRepo.GetBranchCommitID(branchName) | commitID, _ := ctx.Repo.GitRepo.GetBranchCommitID(branchName) | ||||
| req := &grampus.GenerateTrainJobReq{ | req := &grampus.GenerateTrainJobReq{ | ||||
| JobName: jobName, | |||||
| DisplayJobName: displayJobName, | |||||
| ComputeResource: models.GPUResource, | |||||
| ProcessType: grampus.ProcessorTypeGPU, | |||||
| Command: command, | |||||
| ImageUrl: image, | |||||
| Description: description, | |||||
| BootFile: bootFile, | |||||
| Uuid: uuid, | |||||
| CommitID: commitID, | |||||
| BranchName: branchName, | |||||
| Params: form.Params, | |||||
| EngineName: image, | |||||
| DatasetName: attachment.Name, | |||||
| JobName: jobName, | |||||
| DisplayJobName: displayJobName, | |||||
| ComputeResource: models.GPUResource, | |||||
| ProcessType: grampus.ProcessorTypeGPU, | |||||
| Command: command, | |||||
| ImageUrl: image, | |||||
| Description: description, | |||||
| BootFile: bootFile, | |||||
| Uuid: uuid, | |||||
| CommitID: commitID, | |||||
| BranchName: branchName, | |||||
| Params: form.Params, | |||||
| EngineName: image, | |||||
| DatasetNames: datasetNames, | |||||
| DatasetInfos: datasetInfos, | |||||
| IsLatestVersion: modelarts.IsLatestVersion, | IsLatestVersion: modelarts.IsLatestVersion, | ||||
| VersionCount: modelarts.VersionCountOne, | VersionCount: modelarts.VersionCountOne, | ||||
| WorkServerNumber: 1, | WorkServerNumber: 1, | ||||
| Spec: spec, | Spec: spec, | ||||
| } | } | ||||
| if form.ModelName != "" { //使用预训练模型训练 | |||||
| req.ModelName = form.ModelName | |||||
| req.LabelName = form.LabelName | |||||
| req.CkptName = form.CkptName | |||||
| req.ModelVersion = form.ModelVersion | |||||
| req.PreTrainModelUrl = form.PreTrainModelUrl | |||||
| } | |||||
| err = grampus.GenerateTrainJob(ctx, req) | err = grampus.GenerateTrainJob(ctx, req) | ||||
| if err != nil { | if err != nil { | ||||
| log.Error("GenerateTrainJob failed:%v", err.Error(), ctx.Data["MsgID"]) | log.Error("GenerateTrainJob failed:%v", err.Error(), ctx.Data["MsgID"]) | ||||
| grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) | grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) | ||||
| ctx.RenderWithErr(err.Error(), tplGrampusTrainJobGPUNew, &form) | |||||
| ctx.RenderWithErr(err.Error(), tpl, &form) | |||||
| return | return | ||||
| } | } | ||||
| ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/train-job") | ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/train-job") | ||||
| } | } | ||||
| func getPreTrainModelPath(pretrainModelDir string, fileName string) string { | |||||
| index := strings.Index(pretrainModelDir, "/") | |||||
| if index > 0 { | |||||
| filterBucket := pretrainModelDir[index+1:] | |||||
| return filterBucket + fileName | |||||
| } else { | |||||
| return "" | |||||
| } | |||||
| } | |||||
| func GrampusTrainJobVersionCreate(ctx *context.Context, form auth.CreateGrampusTrainJobForm) { | |||||
| ctx.Data["IsCreate"] = false | |||||
| computeResource := ctx.Query("compute_resource") | |||||
| if computeResource == models.GPUResource { | |||||
| GrampusTrainJobGpuCreate(ctx, form) | |||||
| } else if computeResource == models.NPUResource { | |||||
| GrampusTrainJobNpuCreate(ctx, form) | |||||
| } else { | |||||
| ctx.ServerError("resource error", errors.New("compute resource is not support")) | |||||
| return | |||||
| } | |||||
| } | |||||
| func checkSpecialPool(ctx *context.Context, resourceType string) string { | func checkSpecialPool(ctx *context.Context, resourceType string) string { | ||||
| grampus.InitSpecialPool() | grampus.InitSpecialPool() | ||||
| if grampus.SpecialPools != nil { | if grampus.SpecialPools != nil { | ||||
| @@ -409,6 +516,7 @@ func checkSpecialPool(ctx *context.Context, resourceType string) string { | |||||
| } | } | ||||
| func GrampusTrainJobNpuCreate(ctx *context.Context, form auth.CreateGrampusTrainJobForm) { | func GrampusTrainJobNpuCreate(ctx *context.Context, form auth.CreateGrampusTrainJobForm) { | ||||
| ctx.Data["IsCreate"] = true | |||||
| displayJobName := form.DisplayJobName | displayJobName := form.DisplayJobName | ||||
| jobName := util.ConvertDisplayJobNameToJobName(displayJobName) | jobName := util.ConvertDisplayJobNameToJobName(displayJobName) | ||||
| uuid := form.Attachment | uuid := form.Attachment | ||||
| @@ -418,30 +526,34 @@ func GrampusTrainJobNpuCreate(ctx *context.Context, form auth.CreateGrampusTrain | |||||
| repo := ctx.Repo.Repository | repo := ctx.Repo.Repository | ||||
| codeLocalPath := setting.JobPath + jobName + modelarts.CodePath | codeLocalPath := setting.JobPath + jobName + modelarts.CodePath | ||||
| codeObsPath := grampus.JobPath + jobName + modelarts.CodePath | codeObsPath := grampus.JobPath + jobName + modelarts.CodePath | ||||
| dataObsPath := setting.BasePath + path.Join(uuid[0:1], uuid[1:2]) + "/" + uuid + "/" | |||||
| //dataObsPath := setting.BasePath + path.Join(uuid[0:1], uuid[1:2]) + "/" + uuid + "/" | |||||
| branchName := form.BranchName | branchName := form.BranchName | ||||
| isLatestVersion := modelarts.IsLatestVersion | isLatestVersion := modelarts.IsLatestVersion | ||||
| versionCount := modelarts.VersionCountOne | versionCount := modelarts.VersionCountOne | ||||
| engineName := form.EngineName | engineName := form.EngineName | ||||
| tpl := tplGrampusTrainJobNPUNew | |||||
| if !jobNamePattern.MatchString(displayJobName) { | |||||
| lock := redis_lock.NewDistributeLock(redis_key.CloudbrainBindingJobNameKey(fmt.Sprint(repo.ID), string(models.JobTypeTrain), displayJobName)) | |||||
| isOk, err := lock.Lock(models.CloudbrainKeyDuration) | |||||
| if !isOk { | |||||
| log.Error("lock processed failed:%v", err, ctx.Data["MsgID"]) | |||||
| grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) | grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) | ||||
| ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_jobname_err"), tplGrampusTrainJobNPUNew, &form) | |||||
| ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_samejob_err"), tplGrampusTrainJobNPUNew, &form) | |||||
| return | return | ||||
| } | } | ||||
| defer lock.UnLock() | |||||
| bootFileExist, err := ctx.Repo.FileExists(bootFile, branchName) | |||||
| if err != nil || !bootFileExist { | |||||
| log.Error("Get bootfile error:", err, ctx.Data["MsgID"]) | |||||
| if !jobNamePattern.MatchString(displayJobName) { | |||||
| grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) | grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) | ||||
| ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_bootfile_err"), tplGrampusTrainJobNPUNew, &form) | |||||
| ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_jobname_err"), tpl, &form) | |||||
| return | return | ||||
| } | } | ||||
| errStr := checkSpecialPool(ctx, "NPU") | |||||
| if errStr != "" { | |||||
| bootFileExist, err := ctx.Repo.FileExists(bootFile, branchName) | |||||
| if err != nil || !bootFileExist { | |||||
| log.Error("Get bootfile error:", err, ctx.Data["MsgID"]) | |||||
| grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) | grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) | ||||
| ctx.RenderWithErr(errStr, tplGrampusTrainJobGPUNew, &form) | |||||
| ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_bootfile_err"), tpl, &form) | |||||
| return | return | ||||
| } | } | ||||
| @@ -450,13 +562,13 @@ func GrampusTrainJobNpuCreate(ctx *context.Context, form auth.CreateGrampusTrain | |||||
| if err != nil { | if err != nil { | ||||
| log.Error("GetGrampusCountByUserID failed:%v", err, ctx.Data["MsgID"]) | log.Error("GetGrampusCountByUserID failed:%v", err, ctx.Data["MsgID"]) | ||||
| grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) | grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) | ||||
| ctx.RenderWithErr("system error", tplGrampusTrainJobNPUNew, &form) | |||||
| ctx.RenderWithErr("system error", tpl, &form) | |||||
| return | return | ||||
| } else { | } else { | ||||
| if count >= 1 { | if count >= 1 { | ||||
| log.Error("the user already has running or waiting task", ctx.Data["MsgID"]) | log.Error("the user already has running or waiting task", ctx.Data["MsgID"]) | ||||
| grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) | grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) | ||||
| ctx.RenderWithErr("you have already a running or waiting task, can not create more", tplGrampusTrainJobNPUNew, &form) | |||||
| ctx.RenderWithErr("you have already a running or waiting task, can not create more", tpl, &form) | |||||
| return | return | ||||
| } | } | ||||
| } | } | ||||
| @@ -465,7 +577,7 @@ func GrampusTrainJobNpuCreate(ctx *context.Context, form auth.CreateGrampusTrain | |||||
| if err := grampusParamCheckCreateTrainJob(form); err != nil { | if err := grampusParamCheckCreateTrainJob(form); err != nil { | ||||
| log.Error("paramCheckCreateTrainJob failed:(%v)", err) | log.Error("paramCheckCreateTrainJob failed:(%v)", err) | ||||
| grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) | grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) | ||||
| ctx.RenderWithErr(err.Error(), tplGrampusTrainJobNPUNew, &form) | |||||
| ctx.RenderWithErr(err.Error(), tpl, &form) | |||||
| return | return | ||||
| } | } | ||||
| @@ -475,14 +587,14 @@ func GrampusTrainJobNpuCreate(ctx *context.Context, form auth.CreateGrampusTrain | |||||
| if len(tasks) != 0 { | if len(tasks) != 0 { | ||||
| log.Error("the job name did already exist", ctx.Data["MsgID"]) | log.Error("the job name did already exist", ctx.Data["MsgID"]) | ||||
| grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) | grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) | ||||
| ctx.RenderWithErr("the job name did already exist", tplGrampusTrainJobNPUNew, &form) | |||||
| ctx.RenderWithErr("the job name did already exist", tpl, &form) | |||||
| return | return | ||||
| } | } | ||||
| } else { | } else { | ||||
| if !models.IsErrJobNotExist(err) { | if !models.IsErrJobNotExist(err) { | ||||
| log.Error("system error, %v", err, ctx.Data["MsgID"]) | log.Error("system error, %v", err, ctx.Data["MsgID"]) | ||||
| grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) | grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) | ||||
| ctx.RenderWithErr("system error", tplGrampusTrainJobNPUNew, &form) | |||||
| ctx.RenderWithErr("system error", tpl, &form) | |||||
| return | return | ||||
| } | } | ||||
| } | } | ||||
| @@ -495,7 +607,7 @@ func GrampusTrainJobNpuCreate(ctx *context.Context, form auth.CreateGrampusTrain | |||||
| }) | }) | ||||
| if err != nil || spec == nil { | if err != nil || spec == nil { | ||||
| grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) | grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) | ||||
| ctx.RenderWithErr("Resource specification not available", tplGrampusTrainJobNPUNew, &form) | |||||
| ctx.RenderWithErr("Resource specification not available", tpl, &form) | |||||
| return | return | ||||
| } | } | ||||
| if !account.IsPointBalanceEnough(ctx.User.ID, spec.UnitPrice) { | if !account.IsPointBalanceEnough(ctx.User.ID, spec.UnitPrice) { | ||||
| @@ -506,11 +618,11 @@ func GrampusTrainJobNpuCreate(ctx *context.Context, form auth.CreateGrampusTrain | |||||
| } | } | ||||
| //check dataset | //check dataset | ||||
| attachment, err := models.GetAttachmentByUUID(uuid) | |||||
| datasetInfos, datasetNames, err := models.GetDatasetInfo(uuid, models.NPU) | |||||
| if err != nil { | if err != nil { | ||||
| log.Error("GetAttachmentByUUID failed:", err.Error(), ctx.Data["MsgID"]) | |||||
| log.Error("GetDatasetInfo failed: %v", err, ctx.Data["MsgID"]) | |||||
| grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) | grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) | ||||
| ctx.RenderWithErr("dataset is not exist", tplGrampusTrainJobNPUNew, &form) | |||||
| ctx.RenderWithErr(ctx.Tr("cloudbrain.error.dataset_select"), tpl, &form) | |||||
| return | return | ||||
| } | } | ||||
| @@ -523,7 +635,7 @@ func GrampusTrainJobNpuCreate(ctx *context.Context, form auth.CreateGrampusTrain | |||||
| if err := downloadZipCode(ctx, codeLocalPath, branchName); err != nil { | if err := downloadZipCode(ctx, codeLocalPath, branchName); err != nil { | ||||
| log.Error("downloadZipCode failed, server timed out: %s (%v)", repo.FullName(), err) | log.Error("downloadZipCode failed, server timed out: %s (%v)", repo.FullName(), err) | ||||
| grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) | grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) | ||||
| ctx.RenderWithErr(ctx.Tr("cloudbrain.load_code_failed"), tplGrampusTrainJobNPUNew, &form) | |||||
| ctx.RenderWithErr(ctx.Tr("cloudbrain.load_code_failed"), tpl, &form) | |||||
| return | return | ||||
| } | } | ||||
| @@ -531,23 +643,36 @@ func GrampusTrainJobNpuCreate(ctx *context.Context, form auth.CreateGrampusTrain | |||||
| if err := obsMkdir(setting.CodePathPrefix + jobName + modelarts.OutputPath); err != nil { | if err := obsMkdir(setting.CodePathPrefix + jobName + modelarts.OutputPath); err != nil { | ||||
| log.Error("Failed to obsMkdir_output: %s (%v)", repo.FullName(), err) | log.Error("Failed to obsMkdir_output: %s (%v)", repo.FullName(), err) | ||||
| grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) | grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) | ||||
| ctx.RenderWithErr(ctx.Tr("cloudbrain.load_code_failed"), tplGrampusTrainJobNPUNew, &form) | |||||
| ctx.RenderWithErr(ctx.Tr("cloudbrain.load_code_failed"), tpl, &form) | |||||
| return | return | ||||
| } | } | ||||
| if err := uploadCodeToObs(codeLocalPath, jobName, ""); err != nil { | if err := uploadCodeToObs(codeLocalPath, jobName, ""); err != nil { | ||||
| log.Error("Failed to uploadCodeToObs: %s (%v)", repo.FullName(), err) | log.Error("Failed to uploadCodeToObs: %s (%v)", repo.FullName(), err) | ||||
| grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) | grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) | ||||
| ctx.RenderWithErr(ctx.Tr("cloudbrain.load_code_failed"), tplGrampusTrainJobNPUNew, &form) | |||||
| ctx.RenderWithErr(ctx.Tr("cloudbrain.load_code_failed"), tpl, &form) | |||||
| return | return | ||||
| } | } | ||||
| var datasetRemotePath, allFileName string | |||||
| for _, datasetInfo := range datasetInfos { | |||||
| if datasetRemotePath == "" { | |||||
| datasetRemotePath = datasetInfo.DataLocalPath + "'" + datasetInfo.FullName + "'" | |||||
| allFileName = datasetInfo.FullName | |||||
| } else { | |||||
| datasetRemotePath = datasetRemotePath + ";" + datasetInfo.DataLocalPath + "'" + datasetInfo.FullName + "'" | |||||
| allFileName = allFileName + ";" + datasetInfo.FullName | |||||
| } | |||||
| } | |||||
| //prepare command | //prepare command | ||||
| command, err := generateCommand(repo.Name, grampus.ProcessorTypeNPU, codeObsPath+cloudbrain.DefaultBranchName+".zip", dataObsPath+"'"+attachment.Name+"'", bootFile, params, setting.CodePathPrefix+jobName+modelarts.OutputPath, attachment.Name) | |||||
| preTrainModelPath := getPreTrainModelPath(form.PreTrainModelUrl, form.CkptName) | |||||
| command, err := generateCommand(repo.Name, grampus.ProcessorTypeNPU, codeObsPath+cloudbrain.DefaultBranchName+".zip", datasetRemotePath, bootFile, params, setting.CodePathPrefix+jobName+modelarts.OutputPath, allFileName, preTrainModelPath, form.CkptName) | |||||
| if err != nil { | if err != nil { | ||||
| log.Error("Failed to generateCommand: %s (%v)", displayJobName, err, ctx.Data["MsgID"]) | log.Error("Failed to generateCommand: %s (%v)", displayJobName, err, ctx.Data["MsgID"]) | ||||
| grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) | grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) | ||||
| ctx.RenderWithErr("Create task failed, internal error", tplGrampusTrainJobNPUNew, &form) | |||||
| ctx.RenderWithErr("Create task failed, internal error", tpl, &form) | |||||
| return | return | ||||
| } | } | ||||
| @@ -560,7 +685,6 @@ func GrampusTrainJobNpuCreate(ctx *context.Context, form auth.CreateGrampusTrain | |||||
| ProcessType: grampus.ProcessorTypeNPU, | ProcessType: grampus.ProcessorTypeNPU, | ||||
| Command: command, | Command: command, | ||||
| ImageId: form.ImageID, | ImageId: form.ImageID, | ||||
| DataUrl: dataObsPath, | |||||
| Description: description, | Description: description, | ||||
| CodeObsPath: codeObsPath, | CodeObsPath: codeObsPath, | ||||
| BootFileUrl: codeObsPath + bootFile, | BootFileUrl: codeObsPath + bootFile, | ||||
| @@ -574,15 +698,24 @@ func GrampusTrainJobNpuCreate(ctx *context.Context, form auth.CreateGrampusTrain | |||||
| EngineName: engineName, | EngineName: engineName, | ||||
| VersionCount: versionCount, | VersionCount: versionCount, | ||||
| TotalVersionCount: modelarts.TotalVersionCount, | TotalVersionCount: modelarts.TotalVersionCount, | ||||
| DatasetName: attachment.Name, | |||||
| DatasetNames: datasetNames, | |||||
| DatasetInfos: datasetInfos, | |||||
| Spec: spec, | Spec: spec, | ||||
| } | } | ||||
| if form.ModelName != "" { //使用预训练模型训练 | |||||
| req.ModelName = form.ModelName | |||||
| req.LabelName = form.LabelName | |||||
| req.CkptName = form.CkptName | |||||
| req.ModelVersion = form.ModelVersion | |||||
| req.PreTrainModelUrl = form.PreTrainModelUrl | |||||
| } | |||||
| err = grampus.GenerateTrainJob(ctx, req) | err = grampus.GenerateTrainJob(ctx, req) | ||||
| if err != nil { | if err != nil { | ||||
| log.Error("GenerateTrainJob failed:%v", err.Error()) | log.Error("GenerateTrainJob failed:%v", err.Error()) | ||||
| grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) | grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) | ||||
| ctx.RenderWithErr(err.Error(), tplGrampusTrainJobNPUNew, &form) | |||||
| ctx.RenderWithErr(err.Error(), tpl, &form) | |||||
| return | return | ||||
| } | } | ||||
| ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/train-job") | ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/train-job") | ||||
| @@ -709,6 +842,9 @@ func GrampusTrainJobShow(ctx *context.Context) { | |||||
| task.Status = grampus.TransTrainJobStatus(result.JobInfo.Status) | task.Status = grampus.TransTrainJobStatus(result.JobInfo.Status) | ||||
| if task.Status != result.JobInfo.Status || result.JobInfo.Status == models.GrampusStatusRunning { | if task.Status != result.JobInfo.Status || result.JobInfo.Status == models.GrampusStatusRunning { | ||||
| task.Duration = result.JobInfo.RunSec | task.Duration = result.JobInfo.RunSec | ||||
| if task.Duration < 0 { | |||||
| task.Duration = 0 | |||||
| } | |||||
| task.TrainJobDuration = models.ConvertDurationToStr(task.Duration) | task.TrainJobDuration = models.ConvertDurationToStr(task.Duration) | ||||
| if task.StartTime == 0 && result.JobInfo.StartedAt > 0 { | if task.StartTime == 0 && result.JobInfo.StartedAt > 0 { | ||||
| @@ -826,7 +962,7 @@ func GrampusGetLog(ctx *context.Context) { | |||||
| return | return | ||||
| } | } | ||||
| func generateCommand(repoName, processorType, codeRemotePath, dataRemotePath, bootFile, paramSrc, outputRemotePath, datasetName string) (string, error) { | |||||
| func generateCommand(repoName, processorType, codeRemotePath, dataRemotePath, bootFile, paramSrc, outputRemotePath, datasetName, pretrainModelPath, pretrainModelFileName string) (string, error) { | |||||
| var command string | var command string | ||||
| workDir := grampus.NpuWorkDir | workDir := grampus.NpuWorkDir | ||||
| @@ -834,22 +970,22 @@ func generateCommand(repoName, processorType, codeRemotePath, dataRemotePath, bo | |||||
| workDir = grampus.GpuWorkDir | workDir = grampus.GpuWorkDir | ||||
| } | } | ||||
| command += "pwd;cd " + workDir + grampus.CommandPrepareScript | |||||
| command += "pwd;cd " + workDir + fmt.Sprintf(grampus.CommandPrepareScript, setting.Grampus.SyncScriptProject, setting.Grampus.SyncScriptProject) | |||||
| //download code & dataset | //download code & dataset | ||||
| if processorType == grampus.ProcessorTypeNPU { | if processorType == grampus.ProcessorTypeNPU { | ||||
| commandDownload := "./downloader_for_obs " + setting.Bucket + " " + codeRemotePath + " " + grampus.CodeArchiveName + " " + dataRemotePath + " '" + datasetName + "';" | |||||
| commandDownload := "./downloader_for_obs " + setting.Bucket + " " + codeRemotePath + " " + grampus.CodeArchiveName + " '" + dataRemotePath + "' '" + datasetName + "'" | |||||
| commandDownload = processPretrainModelParameter(pretrainModelPath, pretrainModelFileName, commandDownload) | |||||
| command += commandDownload | command += commandDownload | ||||
| } else if processorType == grampus.ProcessorTypeGPU { | } else if processorType == grampus.ProcessorTypeGPU { | ||||
| commandDownload := "./downloader_for_minio " + setting.Grampus.Env + " " + codeRemotePath + " " + grampus.CodeArchiveName + " " + dataRemotePath + " '" + datasetName + "';" | |||||
| commandDownload := "./downloader_for_minio " + setting.Grampus.Env + " " + codeRemotePath + " " + grampus.CodeArchiveName + " '" + dataRemotePath + "' '" + datasetName + "'" | |||||
| commandDownload = processPretrainModelParameter(pretrainModelPath, pretrainModelFileName, commandDownload) | |||||
| command += commandDownload | command += commandDownload | ||||
| } | } | ||||
| //unzip code & dataset | //unzip code & dataset | ||||
| toolUnzip := "unzip -q '" | |||||
| if strings.HasSuffix(datasetName, ".tar.gz") { | |||||
| toolUnzip = "tar -zxvf '" | |||||
| } | |||||
| commandUnzip := "cd " + workDir + "code;unzip -q master.zip;echo \"start to unzip dataset\";cd " + workDir + "dataset;" + toolUnzip + datasetName + "';" | |||||
| unZipDatasetCommand := generateDatasetUnzipCommand(datasetName) | |||||
| commandUnzip := "cd " + workDir + "code;unzip -q master.zip;echo \"start to unzip dataset\";cd " + workDir + "dataset;" + unZipDatasetCommand | |||||
| command += commandUnzip | command += commandUnzip | ||||
| command += "echo \"unzip finished;start to exec code;\";" | command += "echo \"unzip finished;start to exec code;\";" | ||||
| @@ -880,6 +1016,10 @@ func generateCommand(repoName, processorType, codeRemotePath, dataRemotePath, bo | |||||
| } | } | ||||
| } | } | ||||
| if pretrainModelFileName != "" { | |||||
| paramCode += " --pretrainmodelname" + "=" + pretrainModelFileName | |||||
| } | |||||
| var commandCode string | var commandCode string | ||||
| if processorType == grampus.ProcessorTypeNPU { | if processorType == grampus.ProcessorTypeNPU { | ||||
| commandCode = "/bin/bash /home/work/run_train_for_openi.sh " + workDir + "code/" + strings.ToLower(repoName) + "/" + bootFile + " /tmp/log/train.log" + paramCode + ";" | commandCode = "/bin/bash /home/work/run_train_for_openi.sh " + workDir + "code/" + strings.ToLower(repoName) + "/" + bootFile + " /tmp/log/train.log" + paramCode + ";" | ||||
| @@ -895,10 +1035,10 @@ func generateCommand(repoName, processorType, codeRemotePath, dataRemotePath, bo | |||||
| //upload models | //upload models | ||||
| if processorType == grampus.ProcessorTypeNPU { | if processorType == grampus.ProcessorTypeNPU { | ||||
| commandUpload := "cd " + workDir + "script_for_grampus/;./uploader_for_npu " + setting.Bucket + " " + outputRemotePath + " " + workDir + "output/;" | |||||
| commandUpload := "cd " + workDir + setting.Grampus.SyncScriptProject + "/;./uploader_for_npu " + setting.Bucket + " " + outputRemotePath + " " + workDir + "output/;" | |||||
| command += commandUpload | command += commandUpload | ||||
| } else if processorType == grampus.ProcessorTypeGPU { | } else if processorType == grampus.ProcessorTypeGPU { | ||||
| commandUpload := "cd " + workDir + "script_for_grampus/;./uploader_for_gpu " + setting.Grampus.Env + " " + outputRemotePath + " " + workDir + "output/;" | |||||
| commandUpload := "cd " + workDir + setting.Grampus.SyncScriptProject + "/;./uploader_for_gpu " + setting.Grampus.Env + " " + outputRemotePath + " " + workDir + "output/;" | |||||
| command += commandUpload | command += commandUpload | ||||
| } | } | ||||
| @@ -909,6 +1049,38 @@ func generateCommand(repoName, processorType, codeRemotePath, dataRemotePath, bo | |||||
| return command, nil | return command, nil | ||||
| } | } | ||||
| func processPretrainModelParameter(pretrainModelPath string, pretrainModelFileName string, commandDownload string) string { | |||||
| commandDownloadTemp := commandDownload | |||||
| if pretrainModelPath != "" { | |||||
| commandDownloadTemp += " '" + pretrainModelPath + "' '" + pretrainModelFileName + "'" | |||||
| } | |||||
| commandDownloadTemp += ";" | |||||
| return commandDownloadTemp | |||||
| } | |||||
| func generateDatasetUnzipCommand(datasetName string) string { | |||||
| var unZipDatasetCommand string | |||||
| datasetNameArray := strings.Split(datasetName, ";") | |||||
| if len(datasetNameArray) == 1 { //单数据集 | |||||
| unZipDatasetCommand = "unzip -q '" + datasetName + "';" | |||||
| if strings.HasSuffix(datasetName, ".tar.gz") { | |||||
| unZipDatasetCommand = "tar --strip-components=1 -zxvf '" + datasetName + "';" | |||||
| } | |||||
| } else { //多数据集 | |||||
| for _, datasetNameTemp := range datasetNameArray { | |||||
| if strings.HasSuffix(datasetName, ".tar.gz") { | |||||
| unZipDatasetCommand = unZipDatasetCommand + "tar -zxvf '" + datasetName + "';" | |||||
| } else { | |||||
| unZipDatasetCommand = unZipDatasetCommand + "unzip -q '" + datasetNameTemp + "' -d './" + strings.TrimSuffix(datasetNameTemp, ".zip") + "';" | |||||
| } | |||||
| } | |||||
| } | |||||
| return unZipDatasetCommand | |||||
| } | |||||
| func downloadZipCode(ctx *context.Context, codePath, branchName string) error { | func downloadZipCode(ctx *context.Context, codePath, branchName string) error { | ||||
| archiveType := git.ZIP | archiveType := git.ZIP | ||||
| archivePath := codePath | archivePath := codePath | ||||
| @@ -2,9 +2,6 @@ package repo | |||||
| import ( | import ( | ||||
| "archive/zip" | "archive/zip" | ||||
| "code.gitea.io/gitea/modules/modelarts_cd" | |||||
| "code.gitea.io/gitea/services/cloudbrain/resource" | |||||
| "code.gitea.io/gitea/services/reward/point/account" | |||||
| "encoding/json" | "encoding/json" | ||||
| "errors" | "errors" | ||||
| "fmt" | "fmt" | ||||
| @@ -18,6 +15,10 @@ import ( | |||||
| "time" | "time" | ||||
| "unicode/utf8" | "unicode/utf8" | ||||
| "code.gitea.io/gitea/modules/modelarts_cd" | |||||
| "code.gitea.io/gitea/services/cloudbrain/resource" | |||||
| "code.gitea.io/gitea/services/reward/point/account" | |||||
| "code.gitea.io/gitea/models" | "code.gitea.io/gitea/models" | ||||
| "code.gitea.io/gitea/modules/auth" | "code.gitea.io/gitea/modules/auth" | ||||
| "code.gitea.io/gitea/modules/base" | "code.gitea.io/gitea/modules/base" | ||||
| @@ -28,6 +29,8 @@ import ( | |||||
| "code.gitea.io/gitea/modules/modelarts" | "code.gitea.io/gitea/modules/modelarts" | ||||
| "code.gitea.io/gitea/modules/notification" | "code.gitea.io/gitea/modules/notification" | ||||
| "code.gitea.io/gitea/modules/obs" | "code.gitea.io/gitea/modules/obs" | ||||
| "code.gitea.io/gitea/modules/redis/redis_key" | |||||
| "code.gitea.io/gitea/modules/redis/redis_lock" | |||||
| "code.gitea.io/gitea/modules/setting" | "code.gitea.io/gitea/modules/setting" | ||||
| "code.gitea.io/gitea/modules/storage" | "code.gitea.io/gitea/modules/storage" | ||||
| "code.gitea.io/gitea/modules/timeutil" | "code.gitea.io/gitea/modules/timeutil" | ||||
| @@ -210,6 +213,16 @@ func Notebook2Create(ctx *context.Context, form auth.CreateModelArtsNotebookForm | |||||
| imageId := form.ImageId | imageId := form.ImageId | ||||
| repo := ctx.Repo.Repository | repo := ctx.Repo.Repository | ||||
| 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"]) | |||||
| notebookNewDataPrepare(ctx) | |||||
| ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_samejob_err"), tplModelArtsNotebookNew, &form) | |||||
| return | |||||
| } | |||||
| defer lock.UnLock() | |||||
| count, err := models.GetCloudbrainNotebookCountByUserID(ctx.User.ID) | count, err := models.GetCloudbrainNotebookCountByUserID(ctx.User.ID) | ||||
| if err != nil { | if err != nil { | ||||
| log.Error("GetCloudbrainNotebookCountByUserID failed:%v", err, ctx.Data["MsgID"]) | log.Error("GetCloudbrainNotebookCountByUserID failed:%v", err, ctx.Data["MsgID"]) | ||||
| @@ -846,84 +859,6 @@ func setSpecBySpecialPoolConfig(ctx *context.Context, jobType string) { | |||||
| } | } | ||||
| } | } | ||||
| func trainJobErrorNewDataPrepare(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) error { | |||||
| ctx.Data["PageIsCloudBrain"] = true | |||||
| //can, err := canUserCreateTrainJob(ctx.User.ID) | |||||
| //if err != nil { | |||||
| // ctx.ServerError("canUserCreateTrainJob", err) | |||||
| // return | |||||
| //} | |||||
| // | |||||
| //if !can { | |||||
| // log.Error("the user can not create train-job") | |||||
| // ctx.ServerError("the user can not create train-job", fmt.Errorf("the user can not create train-job")) | |||||
| // return | |||||
| //} | |||||
| t := time.Now() | |||||
| var displayJobName = jobNamePrefixValid(cutString(ctx.User.Name, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:] | |||||
| ctx.Data["display_job_name"] = displayJobName | |||||
| attachs, err := models.GetModelArtsTrainAttachments(ctx.User.ID) | |||||
| if err != nil { | |||||
| ctx.ServerError("GetAllUserAttachments failed:", err) | |||||
| return err | |||||
| } | |||||
| ctx.Data["attachments"] = attachs | |||||
| var resourcePools modelarts.ResourcePool | |||||
| if err = json.Unmarshal([]byte(setting.ResourcePools), &resourcePools); err != nil { | |||||
| ctx.ServerError("json.Unmarshal failed:", err) | |||||
| return err | |||||
| } | |||||
| ctx.Data["resource_pools"] = resourcePools.Info | |||||
| var engines modelarts.Engine | |||||
| if err = json.Unmarshal([]byte(setting.Engines), &engines); err != nil { | |||||
| ctx.ServerError("json.Unmarshal failed:", err) | |||||
| return err | |||||
| } | |||||
| ctx.Data["engines"] = engines.Info | |||||
| var versionInfos modelarts.VersionInfo | |||||
| if err = json.Unmarshal([]byte(setting.EngineVersions), &versionInfos); err != nil { | |||||
| ctx.ServerError("json.Unmarshal failed:", err) | |||||
| return err | |||||
| } | |||||
| ctx.Data["engine_versions"] = versionInfos.Version | |||||
| prepareCloudbrainTwoTrainSpecs(ctx) | |||||
| configList, err := getConfigList(modelarts.PerPage, 1, modelarts.SortByCreateTime, "desc", "", modelarts.ConfigTypeCustom) | |||||
| if err != nil { | |||||
| ctx.ServerError("getConfigList failed:", err) | |||||
| return err | |||||
| } | |||||
| var Parameters modelarts.Parameters | |||||
| if err = json.Unmarshal([]byte(form.Params), &Parameters); err != nil { | |||||
| ctx.ServerError("json.Unmarshal failed:", err) | |||||
| return err | |||||
| } | |||||
| ctx.Data["params"] = Parameters.Parameter | |||||
| ctx.Data["config_list"] = configList.ParaConfigs | |||||
| ctx.Data["bootFile"] = form.BootFile | |||||
| ctx.Data["uuid"] = form.Attachment | |||||
| _, datasetNames, err := models.GetDatasetInfo(form.Attachment) | |||||
| if err != nil { | |||||
| log.Error("GetDatasetInfo failed: %v", err, ctx.Data["MsgID"]) | |||||
| return nil | |||||
| } | |||||
| ctx.Data["dataset_name"] = datasetNames | |||||
| ctx.Data["branch_name"] = form.BranchName | |||||
| ctx.Data["datasetType"] = models.TypeCloudBrainTwo | |||||
| waitCount := cloudbrain.GetWaitingCloudbrainCount(models.TypeCloudBrainTwo, "") | |||||
| ctx.Data["WaitCount"] = waitCount | |||||
| setMultiNodeIfConfigureMatch(ctx) | |||||
| return nil | |||||
| } | |||||
| func TrainJobNewVersion(ctx *context.Context) { | func TrainJobNewVersion(ctx *context.Context) { | ||||
| err := trainJobNewVersionDataPrepare(ctx) | err := trainJobNewVersionDataPrepare(ctx) | ||||
| @@ -989,12 +924,7 @@ func trainJobNewVersionDataPrepare(ctx *context.Context) error { | |||||
| ctx.Data["spec_id"] = spec.ID | ctx.Data["spec_id"] = spec.ID | ||||
| } | } | ||||
| var Parameters modelarts.Parameters | |||||
| if err = json.Unmarshal([]byte(task.Parameters), &Parameters); err != nil { | |||||
| ctx.ServerError("json.Unmarshal failed:", err) | |||||
| return err | |||||
| } | |||||
| ctx.Data["params"] = Parameters.Parameter | |||||
| ctx.Data["run_para_list"] = task.Parameters | |||||
| branches, _, err := ctx.Repo.GitRepo.GetBranches(0, 0) | branches, _, err := ctx.Repo.GitRepo.GetBranches(0, 0) | ||||
| if err != nil { | if err != nil { | ||||
| @@ -1017,104 +947,24 @@ func trainJobNewVersionDataPrepare(ctx *context.Context) error { | |||||
| ctx.Data["work_server_number"] = task.WorkServerNumber | ctx.Data["work_server_number"] = task.WorkServerNumber | ||||
| ctx.Data["flavor_name"] = task.FlavorName | ctx.Data["flavor_name"] = task.FlavorName | ||||
| ctx.Data["engine_name"] = task.EngineName | ctx.Data["engine_name"] = task.EngineName | ||||
| ctx.Data["uuid"] = task.Uuid | |||||
| ctx.Data["attachment"] = task.Uuid | |||||
| ctx.Data["flavor_code"] = task.FlavorCode | ctx.Data["flavor_code"] = task.FlavorCode | ||||
| ctx.Data["engine_id"] = task.EngineID | ctx.Data["engine_id"] = task.EngineID | ||||
| ctx.Data["datasetType"] = models.TypeCloudBrainTwo | ctx.Data["datasetType"] = models.TypeCloudBrainTwo | ||||
| configList, err := getConfigList(modelarts.PerPage, 1, modelarts.SortByCreateTime, "desc", "", modelarts.ConfigTypeCustom) | |||||
| if err != nil { | |||||
| ctx.ServerError("getConfigList failed:", err) | |||||
| return err | |||||
| } | |||||
| ctx.Data["config_list"] = configList.ParaConfigs | |||||
| waitCount := cloudbrain.GetWaitingCloudbrainCount(models.TypeCloudBrainTwo, "") | |||||
| ctx.Data["WaitCount"] = waitCount | |||||
| return nil | |||||
| } | |||||
| func versionErrorDataPrepare(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) error { | |||||
| ctx.Data["PageIsCloudBrain"] = true | |||||
| var jobID = ctx.Params(":jobid") | |||||
| // var versionName = ctx.Params(":version-name") | |||||
| var versionName = ctx.Query("version_name") | |||||
| task, err := models.GetCloudbrainByJobIDAndVersionName(jobID, versionName) | |||||
| if err != nil { | |||||
| log.Error("GetCloudbrainByJobIDAndVersionName(%s) failed:%v", jobID, err.Error()) | |||||
| return err | |||||
| } | |||||
| //pretrain model | |||||
| ctx.Data["model_name"] = task.ModelName | |||||
| ctx.Data["model_version"] = task.ModelVersion | |||||
| ctx.Data["ckpt_name"] = task.CkptName | |||||
| ctx.Data["label_names"] = task.LabelName | |||||
| ctx.Data["pre_train_model_url"] = task.PreTrainModelUrl | |||||
| t := time.Now() | |||||
| var jobName = jobNamePrefixValid(cutString(ctx.User.Name, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:] | |||||
| ctx.Data["job_name"] = task.JobName | |||||
| attachs, err := models.GetModelArtsTrainAttachments(ctx.User.ID) | |||||
| if err != nil { | |||||
| ctx.ServerError("GetAllUserAttachments failed:", err) | |||||
| return err | |||||
| } | |||||
| ctx.Data["attachments"] = attachs | |||||
| var resourcePools modelarts.ResourcePool | |||||
| if err = json.Unmarshal([]byte(setting.ResourcePools), &resourcePools); err != nil { | |||||
| ctx.ServerError("json.Unmarshal failed:", err) | |||||
| return err | |||||
| } | |||||
| ctx.Data["resource_pools"] = resourcePools.Info | |||||
| var engines modelarts.Engine | |||||
| if err = json.Unmarshal([]byte(setting.Engines), &engines); err != nil { | |||||
| ctx.ServerError("json.Unmarshal failed:", err) | |||||
| return err | |||||
| } | |||||
| ctx.Data["engines"] = engines.Info | |||||
| var versionInfos modelarts.VersionInfo | |||||
| if err = json.Unmarshal([]byte(setting.EngineVersions), &versionInfos); err != nil { | |||||
| ctx.ServerError("json.Unmarshal failed:", err) | |||||
| return err | |||||
| } | |||||
| ctx.Data["engine_versions"] = versionInfos.Version | |||||
| prepareCloudbrainTwoTrainSpecs(ctx) | |||||
| var Parameters modelarts.Parameters | |||||
| if err = json.Unmarshal([]byte(form.Params), &Parameters); err != nil { | |||||
| ctx.ServerError("json.Unmarshal failed:", err) | |||||
| return err | |||||
| } | |||||
| ctx.Data["params"] = Parameters.Parameter | |||||
| outputObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.OutputPath | |||||
| ctx.Data["train_url"] = outputObsPath | |||||
| branches, _, err := ctx.Repo.GitRepo.GetBranches(0, 0) | |||||
| if err != nil { | |||||
| ctx.ServerError("GetBranches error:", err) | |||||
| return err | |||||
| } | |||||
| ctx.Data["branches"] = branches | |||||
| ctx.Data["description"] = form.Description | |||||
| ctx.Data["dataset_name"] = task.DatasetName | |||||
| ctx.Data["work_server_number"] = form.WorkServerNumber | |||||
| ctx.Data["flavor_name"] = form.FlavorName | |||||
| ctx.Data["engine_name"] = form.EngineName | |||||
| ctx.Data["flavor_code"] = task.FlavorCode | |||||
| ctx.Data["engine_id"] = task.EngineID | |||||
| ctx.Data["version_name"] = form.VersionName | |||||
| ctx.Data["bootFile"] = form.BootFile | |||||
| ctx.Data["uuid"] = form.Attachment | |||||
| ctx.Data["branch_name"] = form.BranchName | |||||
| configList, err := getConfigList(modelarts.PerPage, 1, modelarts.SortByCreateTime, "desc", "", modelarts.ConfigTypeCustom) | configList, err := getConfigList(modelarts.PerPage, 1, modelarts.SortByCreateTime, "desc", "", modelarts.ConfigTypeCustom) | ||||
| if err != nil { | if err != nil { | ||||
| ctx.ServerError("getConfigList failed:", err) | ctx.ServerError("getConfigList failed:", err) | ||||
| return err | return err | ||||
| } | } | ||||
| ctx.Data["config_list"] = configList.ParaConfigs | ctx.Data["config_list"] = configList.ParaConfigs | ||||
| ctx.Data["datasetType"] = models.TypeCloudBrainTwo | |||||
| waitCount := cloudbrain.GetWaitingCloudbrainCount(models.TypeCloudBrainTwo, "") | waitCount := cloudbrain.GetWaitingCloudbrainCount(models.TypeCloudBrainTwo, "") | ||||
| ctx.Data["WaitCount"] = waitCount | ctx.Data["WaitCount"] = waitCount | ||||
| @@ -1148,21 +998,31 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||||
| errStr := checkMultiNode(ctx.User.ID, form.WorkServerNumber) | errStr := checkMultiNode(ctx.User.ID, form.WorkServerNumber) | ||||
| if errStr != "" { | if errStr != "" { | ||||
| trainJobErrorNewDataPrepare(ctx, form) | |||||
| trainJobNewDataPrepare(ctx) | |||||
| ctx.RenderWithErr(ctx.Tr(errStr), tplModelArtsTrainJobNew, &form) | ctx.RenderWithErr(ctx.Tr(errStr), tplModelArtsTrainJobNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| lock := redis_lock.NewDistributeLock(redis_key.CloudbrainBindingJobNameKey(fmt.Sprint(repo.ID), string(models.JobTypeTrain), displayJobName)) | |||||
| isOk, err := lock.Lock(models.CloudbrainKeyDuration) | |||||
| if !isOk { | |||||
| log.Error("lock processed failed:%v", err, ctx.Data["MsgID"]) | |||||
| trainJobNewDataPrepare(ctx) | |||||
| ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_samejob_err"), tplModelArtsTrainJobNew, &form) | |||||
| return | |||||
| } | |||||
| defer lock.UnLock() | |||||
| count, err := models.GetCloudbrainTrainJobCountByUserID(ctx.User.ID) | count, err := models.GetCloudbrainTrainJobCountByUserID(ctx.User.ID) | ||||
| if err != nil { | if err != nil { | ||||
| log.Error("GetCloudbrainTrainJobCountByUserID failed:%v", err, ctx.Data["MsgID"]) | log.Error("GetCloudbrainTrainJobCountByUserID failed:%v", err, ctx.Data["MsgID"]) | ||||
| trainJobErrorNewDataPrepare(ctx, form) | |||||
| trainJobNewDataPrepare(ctx) | |||||
| ctx.RenderWithErr("system error", tplModelArtsTrainJobNew, &form) | ctx.RenderWithErr("system error", tplModelArtsTrainJobNew, &form) | ||||
| return | return | ||||
| } else { | } else { | ||||
| if count >= 1 { | if count >= 1 { | ||||
| log.Error("the user already has running or waiting task", ctx.Data["MsgID"]) | log.Error("the user already has running or waiting task", ctx.Data["MsgID"]) | ||||
| trainJobErrorNewDataPrepare(ctx, form) | |||||
| trainJobNewDataPrepare(ctx) | |||||
| ctx.RenderWithErr("you have already a running or waiting task, can not create more", tplModelArtsTrainJobNew, &form) | ctx.RenderWithErr("you have already a running or waiting task, can not create more", tplModelArtsTrainJobNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| @@ -1170,7 +1030,7 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||||
| if err := paramCheckCreateTrainJob(form); err != nil { | if err := paramCheckCreateTrainJob(form); err != nil { | ||||
| log.Error("paramCheckCreateTrainJob failed:(%v)", err) | log.Error("paramCheckCreateTrainJob failed:(%v)", err) | ||||
| trainJobErrorNewDataPrepare(ctx, form) | |||||
| trainJobNewDataPrepare(ctx) | |||||
| ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobNew, &form) | ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| @@ -1178,7 +1038,7 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||||
| bootFileExist, err := ctx.Repo.FileExists(bootFile, branchName) | bootFileExist, err := ctx.Repo.FileExists(bootFile, branchName) | ||||
| if err != nil || !bootFileExist { | if err != nil || !bootFileExist { | ||||
| log.Error("Get bootfile error:", err) | log.Error("Get bootfile error:", err) | ||||
| trainJobErrorNewDataPrepare(ctx, form) | |||||
| trainJobNewDataPrepare(ctx) | |||||
| ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_bootfile_err"), tplModelArtsTrainJobNew, &form) | ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_bootfile_err"), tplModelArtsTrainJobNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| @@ -1189,7 +1049,7 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||||
| Cluster: models.OpenICluster, | Cluster: models.OpenICluster, | ||||
| AiCenterCode: models.AICenterOfCloudBrainTwo}) | AiCenterCode: models.AICenterOfCloudBrainTwo}) | ||||
| if err != nil || spec == nil { | if err != nil || spec == nil { | ||||
| trainJobErrorNewDataPrepare(ctx, form) | |||||
| trainJobNewDataPrepare(ctx) | |||||
| ctx.RenderWithErr("Resource specification not available", tplModelArtsTrainJobNew, &form) | ctx.RenderWithErr("Resource specification not available", tplModelArtsTrainJobNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| @@ -1205,14 +1065,14 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||||
| if err == nil { | if err == nil { | ||||
| if len(tasks) != 0 { | if len(tasks) != 0 { | ||||
| log.Error("the job name did already exist", ctx.Data["MsgID"]) | log.Error("the job name did already exist", ctx.Data["MsgID"]) | ||||
| trainJobErrorNewDataPrepare(ctx, form) | |||||
| trainJobNewDataPrepare(ctx) | |||||
| ctx.RenderWithErr("the job name did already exist", tplModelArtsTrainJobNew, &form) | ctx.RenderWithErr("the job name did already exist", tplModelArtsTrainJobNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| } else { | } else { | ||||
| if !models.IsErrJobNotExist(err) { | if !models.IsErrJobNotExist(err) { | ||||
| log.Error("system error, %v", err, ctx.Data["MsgID"]) | log.Error("system error, %v", err, ctx.Data["MsgID"]) | ||||
| trainJobErrorNewDataPrepare(ctx, form) | |||||
| trainJobNewDataPrepare(ctx) | |||||
| ctx.RenderWithErr("system error", tplModelArtsTrainJobNew, &form) | ctx.RenderWithErr("system error", tplModelArtsTrainJobNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| @@ -1229,7 +1089,7 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||||
| if err := downloadCode(repo, codeLocalPath, branchName); err != nil { | if err := downloadCode(repo, codeLocalPath, branchName); err != nil { | ||||
| log.Error("downloadCode failed, server timed out: %s (%v)", repo.FullName(), err) | log.Error("downloadCode failed, server timed out: %s (%v)", repo.FullName(), err) | ||||
| trainJobErrorNewDataPrepare(ctx, form) | |||||
| trainJobNewDataPrepare(ctx) | |||||
| ctx.RenderWithErr(ctx.Tr("cloudbrain.load_code_failed"), tplModelArtsTrainJobNew, &form) | ctx.RenderWithErr(ctx.Tr("cloudbrain.load_code_failed"), tplModelArtsTrainJobNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| @@ -1237,14 +1097,14 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||||
| //todo: upload code (send to file_server todo this work?) | //todo: upload code (send to file_server todo this work?) | ||||
| if err := obsMkdir(setting.CodePathPrefix + jobName + modelarts.OutputPath + VersionOutputPath + "/"); err != nil { | if err := obsMkdir(setting.CodePathPrefix + jobName + modelarts.OutputPath + VersionOutputPath + "/"); err != nil { | ||||
| log.Error("Failed to obsMkdir_output: %s (%v)", repo.FullName(), err) | log.Error("Failed to obsMkdir_output: %s (%v)", repo.FullName(), err) | ||||
| trainJobErrorNewDataPrepare(ctx, form) | |||||
| trainJobNewDataPrepare(ctx) | |||||
| ctx.RenderWithErr("Failed to obsMkdir_output", tplModelArtsTrainJobNew, &form) | ctx.RenderWithErr("Failed to obsMkdir_output", tplModelArtsTrainJobNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| if err := obsMkdir(setting.CodePathPrefix + jobName + modelarts.LogPath + VersionOutputPath + "/"); err != nil { | if err := obsMkdir(setting.CodePathPrefix + jobName + modelarts.LogPath + VersionOutputPath + "/"); err != nil { | ||||
| log.Error("Failed to obsMkdir_log: %s (%v)", repo.FullName(), err) | log.Error("Failed to obsMkdir_log: %s (%v)", repo.FullName(), err) | ||||
| trainJobErrorNewDataPrepare(ctx, form) | |||||
| trainJobNewDataPrepare(ctx) | |||||
| ctx.RenderWithErr("Failed to obsMkdir_log", tplModelArtsTrainJobNew, &form) | ctx.RenderWithErr("Failed to obsMkdir_log", tplModelArtsTrainJobNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| @@ -1253,7 +1113,7 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||||
| if err := uploadCodeToObs(codeLocalPath, jobName, ""); err != nil { | if err := uploadCodeToObs(codeLocalPath, jobName, ""); err != nil { | ||||
| // if err := uploadCodeToObs(codeLocalPath, jobName, parentDir); err != nil { | // if err := uploadCodeToObs(codeLocalPath, jobName, parentDir); err != nil { | ||||
| log.Error("Failed to uploadCodeToObs: %s (%v)", repo.FullName(), err) | log.Error("Failed to uploadCodeToObs: %s (%v)", repo.FullName(), err) | ||||
| trainJobErrorNewDataPrepare(ctx, form) | |||||
| trainJobNewDataPrepare(ctx) | |||||
| ctx.RenderWithErr(ctx.Tr("cloudbrain.load_code_failed"), tplModelArtsTrainJobNew, &form) | ctx.RenderWithErr(ctx.Tr("cloudbrain.load_code_failed"), tplModelArtsTrainJobNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| @@ -1265,7 +1125,7 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||||
| err := json.Unmarshal([]byte(params), ¶meters) | err := json.Unmarshal([]byte(params), ¶meters) | ||||
| if err != nil { | if err != nil { | ||||
| log.Error("Failed to Unmarshal params: %s (%v)", params, err) | log.Error("Failed to Unmarshal params: %s (%v)", params, err) | ||||
| trainJobErrorNewDataPrepare(ctx, form) | |||||
| trainJobNewDataPrepare(ctx) | |||||
| ctx.RenderWithErr("运行参数错误", tplModelArtsTrainJobNew, &form) | ctx.RenderWithErr("运行参数错误", tplModelArtsTrainJobNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| @@ -1291,7 +1151,7 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||||
| datasUrlList, dataUrl, datasetNames, isMultiDataset, err := getDatasUrlListByUUIDS(uuid) | datasUrlList, dataUrl, datasetNames, isMultiDataset, err := getDatasUrlListByUUIDS(uuid) | ||||
| if err != nil { | if err != nil { | ||||
| log.Error("Failed to getDatasUrlListByUUIDS: %v", err) | log.Error("Failed to getDatasUrlListByUUIDS: %v", err) | ||||
| trainJobErrorNewDataPrepare(ctx, form) | |||||
| trainJobNewDataPrepare(ctx) | |||||
| ctx.RenderWithErr("Failed to getDatasUrlListByUUIDS:"+err.Error(), tplModelArtsTrainJobNew, &form) | ctx.RenderWithErr("Failed to getDatasUrlListByUUIDS:"+err.Error(), tplModelArtsTrainJobNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| @@ -1299,7 +1159,7 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||||
| jsondatas, err := json.Marshal(datasUrlList) | jsondatas, err := json.Marshal(datasUrlList) | ||||
| if err != nil { | if err != nil { | ||||
| log.Error("Failed to Marshal: %v", err) | log.Error("Failed to Marshal: %v", err) | ||||
| trainJobErrorNewDataPrepare(ctx, form) | |||||
| trainJobNewDataPrepare(ctx) | |||||
| ctx.RenderWithErr("json error:"+err.Error(), tplModelArtsTrainJobNew, &form) | ctx.RenderWithErr("json error:"+err.Error(), tplModelArtsTrainJobNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| @@ -1309,6 +1169,13 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||||
| Value: string(jsondatas), | Value: string(jsondatas), | ||||
| }) | }) | ||||
| } | } | ||||
| if form.ModelName != "" { //使用预训练模型训练 | |||||
| ckptUrl := "/" + form.PreTrainModelUrl + form.CkptName | |||||
| param = append(param, models.Parameter{ | |||||
| Label: modelarts.CkptUrl, | |||||
| Value: "s3:/" + ckptUrl, | |||||
| }) | |||||
| } | |||||
| //save param config | //save param config | ||||
| // if isSaveParam == "on" { | // if isSaveParam == "on" { | ||||
| @@ -1377,6 +1244,15 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||||
| DatasetName: datasetNames, | DatasetName: datasetNames, | ||||
| Spec: spec, | Spec: spec, | ||||
| } | } | ||||
| if form.ModelName != "" { //使用预训练模型训练 | |||||
| req.ModelName = form.ModelName | |||||
| req.LabelName = form.LabelName | |||||
| req.CkptName = form.CkptName | |||||
| req.ModelVersion = form.ModelVersion | |||||
| req.PreTrainModelUrl = form.PreTrainModelUrl | |||||
| } | |||||
| userCommand, userImageUrl := getUserCommand(engineID, req) | userCommand, userImageUrl := getUserCommand(engineID, req) | ||||
| req.UserCommand = userCommand | req.UserCommand = userCommand | ||||
| req.UserImageUrl = userImageUrl | req.UserImageUrl = userImageUrl | ||||
| @@ -1391,7 +1267,7 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||||
| err = modelarts.GenerateTrainJob(ctx, req) | err = modelarts.GenerateTrainJob(ctx, req) | ||||
| if err != nil { | if err != nil { | ||||
| log.Error("GenerateTrainJob failed:%v", err.Error()) | log.Error("GenerateTrainJob failed:%v", err.Error()) | ||||
| trainJobErrorNewDataPrepare(ctx, form) | |||||
| trainJobNewDataPrepare(ctx) | |||||
| ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobNew, &form) | ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| @@ -1476,7 +1352,7 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ | |||||
| errStr := checkMultiNode(ctx.User.ID, form.WorkServerNumber) | errStr := checkMultiNode(ctx.User.ID, form.WorkServerNumber) | ||||
| if errStr != "" { | if errStr != "" { | ||||
| versionErrorDataPrepare(ctx, form) | |||||
| trainJobNewVersionDataPrepare(ctx) | |||||
| ctx.RenderWithErr(ctx.Tr(errStr), tplModelArtsTrainJobVersionNew, &form) | ctx.RenderWithErr(ctx.Tr(errStr), tplModelArtsTrainJobVersionNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| @@ -1484,13 +1360,13 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ | |||||
| count, err := models.GetCloudbrainTrainJobCountByUserID(ctx.User.ID) | count, err := models.GetCloudbrainTrainJobCountByUserID(ctx.User.ID) | ||||
| if err != nil { | if err != nil { | ||||
| log.Error("GetCloudbrainTrainJobCountByUserID failed:%v", err, ctx.Data["MsgID"]) | log.Error("GetCloudbrainTrainJobCountByUserID failed:%v", err, ctx.Data["MsgID"]) | ||||
| versionErrorDataPrepare(ctx, form) | |||||
| trainJobNewVersionDataPrepare(ctx) | |||||
| ctx.RenderWithErr("system error", tplModelArtsTrainJobVersionNew, &form) | ctx.RenderWithErr("system error", tplModelArtsTrainJobVersionNew, &form) | ||||
| return | return | ||||
| } else { | } else { | ||||
| if count >= 1 { | if count >= 1 { | ||||
| log.Error("the user already has running or waiting task", ctx.Data["MsgID"]) | log.Error("the user already has running or waiting task", ctx.Data["MsgID"]) | ||||
| versionErrorDataPrepare(ctx, form) | |||||
| trainJobNewVersionDataPrepare(ctx) | |||||
| ctx.RenderWithErr("you have already a running or waiting task, can not create more", tplModelArtsTrainJobVersionNew, &form) | ctx.RenderWithErr("you have already a running or waiting task, can not create more", tplModelArtsTrainJobVersionNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| @@ -1525,16 +1401,26 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ | |||||
| EngineName := form.EngineName | EngineName := form.EngineName | ||||
| isLatestVersion := modelarts.IsLatestVersion | isLatestVersion := modelarts.IsLatestVersion | ||||
| lock := redis_lock.NewDistributeLock(redis_key.CloudbrainBindingJobNameKey(fmt.Sprint(repo.ID), string(models.JobTypeTrain), displayJobName)) | |||||
| isOk, err := lock.Lock(models.CloudbrainKeyDuration) | |||||
| if !isOk { | |||||
| log.Error("lock processed failed:%v", err, ctx.Data["MsgID"]) | |||||
| trainJobNewVersionDataPrepare(ctx) | |||||
| ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_samejob_err"), tplModelArtsTrainJobVersionNew, &form) | |||||
| return | |||||
| } | |||||
| defer lock.UnLock() | |||||
| canNewJob, _ := canUserCreateTrainJobVersion(ctx, latestTask.UserID) | canNewJob, _ := canUserCreateTrainJobVersion(ctx, latestTask.UserID) | ||||
| if !canNewJob { | if !canNewJob { | ||||
| versionErrorDataPrepare(ctx, form) | |||||
| trainJobNewVersionDataPrepare(ctx) | |||||
| ctx.RenderWithErr("user cann't new trainjob", tplModelArtsTrainJobVersionNew, &form) | ctx.RenderWithErr("user cann't new trainjob", tplModelArtsTrainJobVersionNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| if err := paramCheckCreateTrainJob(form); err != nil { | if err := paramCheckCreateTrainJob(form); err != nil { | ||||
| log.Error("paramCheckCreateTrainJob failed:(%v)", err) | log.Error("paramCheckCreateTrainJob failed:(%v)", err) | ||||
| versionErrorDataPrepare(ctx, form) | |||||
| trainJobNewVersionDataPrepare(ctx) | |||||
| ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobVersionNew, &form) | ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobVersionNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| @@ -1542,7 +1428,7 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ | |||||
| bootFileExist, err := ctx.Repo.FileExists(bootFile, branchName) | bootFileExist, err := ctx.Repo.FileExists(bootFile, branchName) | ||||
| if err != nil || !bootFileExist { | if err != nil || !bootFileExist { | ||||
| log.Error("Get bootfile error:", err) | log.Error("Get bootfile error:", err) | ||||
| versionErrorDataPrepare(ctx, form) | |||||
| trainJobNewVersionDataPrepare(ctx) | |||||
| ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_bootfile_err"), tplModelArtsTrainJobVersionNew, &form) | ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_bootfile_err"), tplModelArtsTrainJobVersionNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| @@ -1553,13 +1439,13 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ | |||||
| Cluster: models.OpenICluster, | Cluster: models.OpenICluster, | ||||
| AiCenterCode: models.AICenterOfCloudBrainTwo}) | AiCenterCode: models.AICenterOfCloudBrainTwo}) | ||||
| if err != nil || spec == nil { | if err != nil || spec == nil { | ||||
| versionErrorDataPrepare(ctx, form) | |||||
| trainJobNewVersionDataPrepare(ctx) | |||||
| ctx.RenderWithErr("Resource specification not available", tplModelArtsTrainJobVersionNew, &form) | ctx.RenderWithErr("Resource specification not available", tplModelArtsTrainJobVersionNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| if !account.IsPointBalanceEnough(ctx.User.ID, spec.UnitPrice) { | if !account.IsPointBalanceEnough(ctx.User.ID, spec.UnitPrice) { | ||||
| log.Error("point balance is not enough,userId=%d specId=%d", ctx.User.ID, spec.ID) | log.Error("point balance is not enough,userId=%d specId=%d", ctx.User.ID, spec.ID) | ||||
| versionErrorDataPrepare(ctx, form) | |||||
| trainJobNewVersionDataPrepare(ctx) | |||||
| ctx.RenderWithErr(ctx.Tr("points.insufficient_points_balance"), tplModelArtsTrainJobVersionNew, &form) | ctx.RenderWithErr(ctx.Tr("points.insufficient_points_balance"), tplModelArtsTrainJobVersionNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| @@ -1574,7 +1460,7 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ | |||||
| commitID, _ := gitRepo.GetBranchCommitID(branchName) | commitID, _ := gitRepo.GetBranchCommitID(branchName) | ||||
| if err := downloadCode(repo, codeLocalPath, branchName); err != nil { | if err := downloadCode(repo, codeLocalPath, branchName); err != nil { | ||||
| log.Error("Failed git clone repo to local(!: %s (%v)", repo.FullName(), err) | log.Error("Failed git clone repo to local(!: %s (%v)", repo.FullName(), err) | ||||
| versionErrorDataPrepare(ctx, form) | |||||
| trainJobNewVersionDataPrepare(ctx) | |||||
| ctx.RenderWithErr(ctx.Tr("cloudbrain.load_code_failed"), tplModelArtsTrainJobVersionNew, &form) | ctx.RenderWithErr(ctx.Tr("cloudbrain.load_code_failed"), tplModelArtsTrainJobVersionNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| @@ -1582,14 +1468,14 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ | |||||
| //todo: upload code (send to file_server todo this work?) | //todo: upload code (send to file_server todo this work?) | ||||
| if err := obsMkdir(setting.CodePathPrefix + jobName + modelarts.OutputPath + VersionOutputPath + "/"); err != nil { | if err := obsMkdir(setting.CodePathPrefix + jobName + modelarts.OutputPath + VersionOutputPath + "/"); err != nil { | ||||
| log.Error("Failed to obsMkdir_output: %s (%v)", repo.FullName(), err) | log.Error("Failed to obsMkdir_output: %s (%v)", repo.FullName(), err) | ||||
| versionErrorDataPrepare(ctx, form) | |||||
| trainJobNewVersionDataPrepare(ctx) | |||||
| ctx.RenderWithErr("Failed to obsMkdir_output", tplModelArtsTrainJobVersionNew, &form) | ctx.RenderWithErr("Failed to obsMkdir_output", tplModelArtsTrainJobVersionNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| if err := obsMkdir(setting.CodePathPrefix + jobName + modelarts.LogPath + VersionOutputPath + "/"); err != nil { | if err := obsMkdir(setting.CodePathPrefix + jobName + modelarts.LogPath + VersionOutputPath + "/"); err != nil { | ||||
| log.Error("Failed to obsMkdir_log: %s (%v)", repo.FullName(), err) | log.Error("Failed to obsMkdir_log: %s (%v)", repo.FullName(), err) | ||||
| versionErrorDataPrepare(ctx, form) | |||||
| trainJobNewVersionDataPrepare(ctx) | |||||
| ctx.RenderWithErr("Failed to obsMkdir_log", tplModelArtsTrainJobVersionNew, &form) | ctx.RenderWithErr("Failed to obsMkdir_log", tplModelArtsTrainJobVersionNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| @@ -1599,7 +1485,7 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ | |||||
| // if err := uploadCodeToObs(codeLocalPath, jobName, ""); err != nil { | // if err := uploadCodeToObs(codeLocalPath, jobName, ""); err != nil { | ||||
| if err := uploadCodeToObs(codeLocalPath, jobName, parentDir); err != nil { | if err := uploadCodeToObs(codeLocalPath, jobName, parentDir); err != nil { | ||||
| log.Error("Failed to uploadCodeToObs: %s (%v)", repo.FullName(), err) | log.Error("Failed to uploadCodeToObs: %s (%v)", repo.FullName(), err) | ||||
| versionErrorDataPrepare(ctx, form) | |||||
| trainJobNewVersionDataPrepare(ctx) | |||||
| ctx.RenderWithErr(ctx.Tr("cloudbrain.load_code_failed"), tplModelArtsTrainJobVersionNew, &form) | ctx.RenderWithErr(ctx.Tr("cloudbrain.load_code_failed"), tplModelArtsTrainJobVersionNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| @@ -1613,7 +1499,7 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ | |||||
| err := json.Unmarshal([]byte(params), ¶meters) | err := json.Unmarshal([]byte(params), ¶meters) | ||||
| if err != nil { | if err != nil { | ||||
| log.Error("Failed to Unmarshal params: %s (%v)", params, err) | log.Error("Failed to Unmarshal params: %s (%v)", params, err) | ||||
| versionErrorDataPrepare(ctx, form) | |||||
| trainJobNewVersionDataPrepare(ctx) | |||||
| ctx.RenderWithErr("运行参数错误", tplModelArtsTrainJobVersionNew, &form) | ctx.RenderWithErr("运行参数错误", tplModelArtsTrainJobVersionNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| @@ -1639,7 +1525,7 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ | |||||
| datasUrlList, dataUrl, datasetNames, isMultiDataset, err := getDatasUrlListByUUIDS(uuid) | datasUrlList, dataUrl, datasetNames, isMultiDataset, err := getDatasUrlListByUUIDS(uuid) | ||||
| if err != nil { | if err != nil { | ||||
| log.Error("Failed to getDatasUrlListByUUIDS: %v", err) | log.Error("Failed to getDatasUrlListByUUIDS: %v", err) | ||||
| versionErrorDataPrepare(ctx, form) | |||||
| trainJobNewVersionDataPrepare(ctx) | |||||
| ctx.RenderWithErr("Failed to getDatasUrlListByUUIDS:"+err.Error(), tplModelArtsTrainJobVersionNew, &form) | ctx.RenderWithErr("Failed to getDatasUrlListByUUIDS:"+err.Error(), tplModelArtsTrainJobVersionNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| @@ -1647,7 +1533,7 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ | |||||
| jsondatas, err := json.Marshal(datasUrlList) | jsondatas, err := json.Marshal(datasUrlList) | ||||
| if err != nil { | if err != nil { | ||||
| log.Error("Failed to Marshal: %v", err) | log.Error("Failed to Marshal: %v", err) | ||||
| versionErrorDataPrepare(ctx, form) | |||||
| trainJobNewVersionDataPrepare(ctx) | |||||
| ctx.RenderWithErr("json error:"+err.Error(), tplModelArtsTrainJobVersionNew, &form) | ctx.RenderWithErr("json error:"+err.Error(), tplModelArtsTrainJobVersionNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| @@ -1658,46 +1544,14 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ | |||||
| }) | }) | ||||
| } | } | ||||
| // //save param config | |||||
| // if isSaveParam == "on" { | |||||
| // saveparams := append(param, models.Parameter{ | |||||
| // Label: modelarts.TrainUrl, | |||||
| // Value: outputObsPath, | |||||
| // }, models.Parameter{ | |||||
| // Label: modelarts.DataUrl, | |||||
| // Value: dataPath, | |||||
| // }) | |||||
| // if form.ParameterTemplateName == "" { | |||||
| // log.Error("ParameterTemplateName is empty") | |||||
| // versionErrorDataPrepare(ctx, form) | |||||
| // ctx.RenderWithErr("保存作业参数时,作业参数名称不能为空", tplModelArtsTrainJobVersionNew, &form) | |||||
| // return | |||||
| // } | |||||
| // _, err := modelarts.CreateTrainJobConfig(models.CreateConfigParams{ | |||||
| // ConfigName: form.ParameterTemplateName, | |||||
| // Description: form.PrameterDescription, | |||||
| // DataUrl: dataPath, | |||||
| // AppUrl: codeObsPath, | |||||
| // BootFileUrl: codeObsPath + bootFile, | |||||
| // TrainUrl: outputObsPath, | |||||
| // Flavor: models.Flavor{ | |||||
| // Code: flavorCode, | |||||
| // }, | |||||
| // WorkServerNum: workServerNumber, | |||||
| // EngineID: int64(engineID), | |||||
| // LogUrl: logObsPath, | |||||
| // PoolID: poolID, | |||||
| // Parameter: saveparams, | |||||
| // }) | |||||
| if form.ModelName != "" { //使用预训练模型训练 | |||||
| ckptUrl := "/" + form.PreTrainModelUrl + form.CkptName | |||||
| param = append(param, models.Parameter{ | |||||
| Label: modelarts.CkptUrl, | |||||
| Value: "s3:/" + ckptUrl, | |||||
| }) | |||||
| } | |||||
| // if err != nil { | |||||
| // log.Error("Failed to CreateTrainJobConfig: %v", err) | |||||
| // versionErrorDataPrepare(ctx, form) | |||||
| // ctx.RenderWithErr("保存作业参数失败:"+err.Error(), tplModelArtsTrainJobVersionNew, &form) | |||||
| // return | |||||
| // } | |||||
| // } | |||||
| task, err := models.GetCloudbrainByJobIDAndVersionName(jobID, PreVersionName) | task, err := models.GetCloudbrainByJobIDAndVersionName(jobID, PreVersionName) | ||||
| if err != nil { | if err != nil { | ||||
| @@ -1732,6 +1586,15 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ | |||||
| DatasetName: datasetNames, | DatasetName: datasetNames, | ||||
| Spec: spec, | Spec: spec, | ||||
| } | } | ||||
| if form.ModelName != "" { //使用预训练模型训练 | |||||
| req.ModelName = form.ModelName | |||||
| req.LabelName = form.LabelName | |||||
| req.CkptName = form.CkptName | |||||
| req.ModelVersion = form.ModelVersion | |||||
| req.PreTrainModelUrl = form.PreTrainModelUrl | |||||
| } | |||||
| userCommand, userImageUrl := getUserCommand(engineID, req) | userCommand, userImageUrl := getUserCommand(engineID, req) | ||||
| req.UserCommand = userCommand | req.UserCommand = userCommand | ||||
| req.UserImageUrl = userImageUrl | req.UserImageUrl = userImageUrl | ||||
| @@ -1739,7 +1602,7 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ | |||||
| err = modelarts.GenerateTrainJobVersion(ctx, req, jobID) | err = modelarts.GenerateTrainJobVersion(ctx, req, jobID) | ||||
| if err != nil { | if err != nil { | ||||
| log.Error("GenerateTrainJob failed:%v", err.Error()) | log.Error("GenerateTrainJob failed:%v", err.Error()) | ||||
| versionErrorDataPrepare(ctx, form) | |||||
| trainJobNewVersionDataPrepare(ctx) | |||||
| ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobVersionNew, &form) | ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobVersionNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| @@ -2136,6 +1999,16 @@ func InferenceJobCreate(ctx *context.Context, form auth.CreateModelArtsInference | |||||
| return | return | ||||
| } | } | ||||
| lock := redis_lock.NewDistributeLock(redis_key.CloudbrainBindingJobNameKey(fmt.Sprint(repo.ID), string(models.JobTypeInference), displayJobName)) | |||||
| isOk, err := lock.Lock(models.CloudbrainKeyDuration) | |||||
| if !isOk { | |||||
| log.Error("lock processed failed:%v", err, ctx.Data["MsgID"]) | |||||
| inferenceJobErrorNewDataPrepare(ctx, form) | |||||
| ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_samejob_err"), tplModelArtsInferenceJobNew, &form) | |||||
| return | |||||
| } | |||||
| defer lock.UnLock() | |||||
| count, err := models.GetCloudbrainInferenceJobCountByUserID(ctx.User.ID) | count, err := models.GetCloudbrainInferenceJobCountByUserID(ctx.User.ID) | ||||
| if err != nil { | if err != nil { | ||||
| log.Error("GetCloudbrainInferenceJobCountByUserID failed:%v", err, ctx.Data["MsgID"]) | log.Error("GetCloudbrainInferenceJobCountByUserID failed:%v", err, ctx.Data["MsgID"]) | ||||
| @@ -8,6 +8,7 @@ import ( | |||||
| "code.gitea.io/gitea/routers/response" | "code.gitea.io/gitea/routers/response" | ||||
| "code.gitea.io/gitea/services/reward" | "code.gitea.io/gitea/services/reward" | ||||
| "code.gitea.io/gitea/services/reward/point/account" | "code.gitea.io/gitea/services/reward/point/account" | ||||
| "code.gitea.io/gitea/services/task" | |||||
| "errors" | "errors" | ||||
| "net/http" | "net/http" | ||||
| ) | ) | ||||
| @@ -92,6 +93,17 @@ func GetRulePage(ctx *context.Context) { | |||||
| ctx.HTML(200, tplPointRule) | ctx.HTML(200, tplPointRule) | ||||
| } | } | ||||
| func GetRuleConfig(ctx *context.Context) { | |||||
| r, err := task.GetPointRule() | |||||
| if err != nil { | |||||
| log.Error("GetRuleConfig error.%v", err) | |||||
| ctx.JSON(http.StatusOK, response.ServerError(err.Error())) | |||||
| return | |||||
| } | |||||
| ctx.JSON(http.StatusOK, response.SuccessWithData(r)) | |||||
| } | |||||
| func GetAdminRewardList(ctx *context.Context) { | func GetAdminRewardList(ctx *context.Context) { | ||||
| opts, err := buildAdminRewardRecordListOpts(ctx) | opts, err := buildAdminRewardRecordListOpts(ctx) | ||||
| if err != nil { | if err != nil { | ||||
| @@ -1159,6 +1159,8 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
| m.Get("/download_model", cloudbrain.AdminOrOwnerOrJobCreaterRightForTrain, repo.CloudBrainDownloadModel) | m.Get("/download_model", cloudbrain.AdminOrOwnerOrJobCreaterRightForTrain, repo.CloudBrainDownloadModel) | ||||
| //m.Get("/get_log", cloudbrain.AdminOrJobCreaterRightForTrain, repo.GetLogFromModelDir) | //m.Get("/get_log", cloudbrain.AdminOrJobCreaterRightForTrain, repo.GetLogFromModelDir) | ||||
| //m.Post("/create_version", reqWechatBind, cloudbrain.AdminOrJobCreaterRightForTrain, bindIgnErr(auth.CreateModelArtsTrainJobForm{}), repo.TrainJobCreateVersion) | //m.Post("/create_version", reqWechatBind, cloudbrain.AdminOrJobCreaterRightForTrain, bindIgnErr(auth.CreateModelArtsTrainJobForm{}), repo.TrainJobCreateVersion) | ||||
| m.Get("/create_version", reqWechatBind, cloudbrain.AdminOrJobCreaterRightForTrain, repo.CloudBrainTrainJobVersionNew) | |||||
| m.Post("/create_version", reqWechatBind, cloudbrain.AdminOrJobCreaterRightForTrain, bindIgnErr(auth.CreateCloudBrainForm{}), repo.CloudBrainTrainJobVersionCreate) | |||||
| }) | }) | ||||
| m.Get("/create", reqWechatBind, reqRepoCloudBrainWriter, context.PointAccount(), repo.CloudBrainTrainJobNew) | m.Get("/create", reqWechatBind, reqRepoCloudBrainWriter, context.PointAccount(), repo.CloudBrainTrainJobNew) | ||||
| m.Post("/create", reqWechatBind, reqRepoCloudBrainWriter, bindIgnErr(auth.CreateCloudBrainForm{}), repo.CloudBrainCreate) | m.Post("/create", reqWechatBind, reqRepoCloudBrainWriter, bindIgnErr(auth.CreateCloudBrainForm{}), repo.CloudBrainCreate) | ||||
| @@ -1181,6 +1183,8 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
| m.Post("/stop", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.GrampusStopJob) | m.Post("/stop", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.GrampusStopJob) | ||||
| m.Post("/del", cloudbrain.AdminOrOwnerOrJobCreaterRightForTrain, repo.GrampusTrainJobDel) | m.Post("/del", cloudbrain.AdminOrOwnerOrJobCreaterRightForTrain, repo.GrampusTrainJobDel) | ||||
| m.Get("/model_download", cloudbrain.AdminOrJobCreaterRightForTrain, repo.ModelDownload) | m.Get("/model_download", cloudbrain.AdminOrJobCreaterRightForTrain, repo.ModelDownload) | ||||
| m.Get("/create_version", reqWechatBind, cloudbrain.AdminOrJobCreaterRightForTrain, repo.GrampusTrainJobVersionNew) | |||||
| m.Post("/create_version", reqWechatBind, cloudbrain.AdminOrJobCreaterRightForTrain, bindIgnErr(auth.CreateGrampusTrainJobForm{}), repo.GrampusTrainJobVersionCreate) | |||||
| }) | }) | ||||
| m.Group("/gpu", func() { | m.Group("/gpu", func() { | ||||
| m.Get("/create", reqWechatBind, reqRepoCloudBrainWriter, context.PointAccount(), repo.GrampusTrainJobGPUNew) | m.Get("/create", reqWechatBind, reqRepoCloudBrainWriter, context.PointAccount(), repo.GrampusTrainJobGPUNew) | ||||
| @@ -1435,6 +1439,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
| m.Group("/reward/point", func() { | m.Group("/reward/point", func() { | ||||
| m.Get("", point.GetPointPage) | m.Get("", point.GetPointPage) | ||||
| m.Get("/rule", point.GetRulePage) | m.Get("/rule", point.GetRulePage) | ||||
| m.Get("/rule/config", point.GetRuleConfig) | |||||
| m.Get("/account", point.GetPointAccount) | m.Get("/account", point.GetPointAccount) | ||||
| m.Get("/record/list", point.GetPointRecordList) | m.Get("/record/list", point.GetPointRecordList) | ||||
| }, reqSignIn) | }, reqSignIn) | ||||
| @@ -11,7 +11,7 @@ import ( | |||||
| func GetSerialNoByRedis() (string, error) { | func GetSerialNoByRedis() (string, error) { | ||||
| now := time.Now() | now := time.Now() | ||||
| r := int64(rand.Intn(4)) + 1 | |||||
| r := int64(rand.Intn(3)) + 1 | |||||
| n, err := redis_client.IncrBy(redis_key.RewardSerialCounter(now), r) | n, err := redis_client.IncrBy(redis_key.RewardSerialCounter(now), r) | ||||
| if err != nil { | if err != nil { | ||||
| log.Error("GetSerialNoByRedis RewardSerialCounter error. %v", err) | log.Error("GetSerialNoByRedis RewardSerialCounter error. %v", err) | ||||
| @@ -20,5 +20,9 @@ func GetSerialNoByRedis() (string, error) { | |||||
| if n == r { | if n == r { | ||||
| redis_client.Expire(redis_key.RewardSerialCounter(now), 2*time.Minute) | redis_client.Expire(redis_key.RewardSerialCounter(now), 2*time.Minute) | ||||
| } | } | ||||
| //when the counter n exceeds 1000, the length of the serial number will become longer | |||||
| if n >= 1000 { | |||||
| return now.Format("200601021504") + fmt.Sprintf("%d", n) + fmt.Sprint(rand.Intn(10)), nil | |||||
| } | |||||
| return now.Format("200601021504") + fmt.Sprintf("%03d", n) + fmt.Sprint(rand.Intn(10)), nil | return now.Format("200601021504") + fmt.Sprintf("%03d", n) + fmt.Sprint(rand.Intn(10)), nil | ||||
| } | } | ||||
| @@ -6,8 +6,10 @@ import ( | |||||
| "code.gitea.io/gitea/modules/redis/redis_client" | "code.gitea.io/gitea/modules/redis/redis_client" | ||||
| "code.gitea.io/gitea/modules/redis/redis_key" | "code.gitea.io/gitea/modules/redis/redis_key" | ||||
| "code.gitea.io/gitea/modules/redis/redis_lock" | "code.gitea.io/gitea/modules/redis/redis_lock" | ||||
| "code.gitea.io/gitea/services/reward/limiter" | |||||
| "encoding/json" | "encoding/json" | ||||
| "errors" | "errors" | ||||
| "fmt" | |||||
| "time" | "time" | ||||
| ) | ) | ||||
| @@ -181,3 +183,46 @@ func DelTaskConfig(id int64, doer *models.User) error { | |||||
| redis_client.Del(redis_key.TaskConfigList()) | redis_client.Del(redis_key.TaskConfigList()) | ||||
| return nil | return nil | ||||
| } | } | ||||
| func GetPointRule() (*models.PointRule, error) { | |||||
| r, err := limiter.GetSingleDailyPointLimitConfig() | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| limiters, err := limiter.GetLimitersByLimitType(models.LimitTypeTask) | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| limiterMap := make(map[string]*models.LimitConfig, 0) | |||||
| for i := 0; i < len(limiters); i++ { | |||||
| limiterMap[limiters[i].LimitCode] = &limiters[i] | |||||
| } | |||||
| taskConfigs, err := GetTaskConfigList() | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| taskRules := make([]models.TaskRule, len(taskConfigs)) | |||||
| for i, taskConfig := range taskConfigs { | |||||
| rule := models.TaskRule{ | |||||
| TaskCode: taskConfig.TaskCode, | |||||
| AwardType: taskConfig.AwardType, | |||||
| AwardAmount: taskConfig.AwardAmount, | |||||
| } | |||||
| limiter := limiterMap[fmt.Sprint(taskConfig.TaskCode)] | |||||
| if limiter != nil { | |||||
| rule.RefreshRate = limiter.RefreshRate | |||||
| rule.LimitNum = limiter.LimitNum | |||||
| } | |||||
| taskRules[i] = rule | |||||
| } | |||||
| pointRule := &models.PointRule{ | |||||
| TaskRules: taskRules, | |||||
| } | |||||
| if r != nil { | |||||
| pointRule.UserDailyLimit = r.LimitNum | |||||
| } | |||||
| return pointRule, nil | |||||
| } | |||||
| @@ -259,6 +259,14 @@ | |||||
| </a> | </a> | ||||
| {{end}} | {{end}} | ||||
| </div> | </div> | ||||
| <!-- 修改任务 --> | |||||
| {{if eq .JobType "TRAIN"}} | |||||
| <div class="ui compact buttons"> | |||||
| <a style="padding: 0.5rem 1rem;" class="ui basic blue button" href="{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}{{if eq .Cloudbrain.Type 1}}/modelarts/train-job/{{.JobID}}{{else if eq .Cloudbrain.Type 0}}/cloudbrain/train-job/{{.JobID}}{{else if eq .Cloudbrain.Type 2}}/grampus/train-job/{{.JobID}}{{end}}/create_version{{if .VersionName}}?version_name={{.VersionName}}{{end}}"> | |||||
| {{$.i18n.Tr "repo.modelarts.modify"}} | |||||
| </a> | |||||
| </div> | |||||
| {{end}} | |||||
| <!-- 删除任务 --> | <!-- 删除任务 --> | ||||
| <form class="ui compact buttons" id="delForm-{{$JobID}}" | <form class="ui compact buttons" id="delForm-{{$JobID}}" | ||||
| action='{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}{{if eq .JobType "BENCHMARK"}}/cloudbrain/benchmark{{else if or (eq .JobType "SNN4IMAGENET") (eq .JobType "BRAINSCORE")}}/cloudbrain{{else if eq .JobType "DEBUG"}}{{if eq .ComputeResource "NPU"}}/modelarts/notebook{{else}}/cloudbrain{{end}}{{else if eq .JobType "TRAIN"}}{{if eq .Cloudbrain.Type 1}}/modelarts/train-job{{else if eq .Cloudbrain.Type 0}}/cloudbrain/train-job{{else if eq .Cloudbrain.Type 2}}/grampus/train-job{{end}}{{else if eq .JobType "INFERENCE"}}{{if eq .Cloudbrain.Type 0}}/cloudbrain/train-job{{end}}{{end}}/{{$JobID}}/del?isadminpage=true' | action='{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}{{if eq .JobType "BENCHMARK"}}/cloudbrain/benchmark{{else if or (eq .JobType "SNN4IMAGENET") (eq .JobType "BRAINSCORE")}}/cloudbrain{{else if eq .JobType "DEBUG"}}{{if eq .ComputeResource "NPU"}}/modelarts/notebook{{else}}/cloudbrain{{end}}{{else if eq .JobType "TRAIN"}}{{if eq .Cloudbrain.Type 1}}/modelarts/train-job{{else if eq .Cloudbrain.Type 0}}/cloudbrain/train-job{{else if eq .Cloudbrain.Type 2}}/grampus/train-job{{end}}{{else if eq .JobType "INFERENCE"}}{{if eq .Cloudbrain.Type 0}}/cloudbrain/train-job{{end}}{{end}}/{{$JobID}}/del?isadminpage=true' | ||||
| @@ -20,7 +20,7 @@ | |||||
| <div class="column ui vertical text menu"> | <div class="column ui vertical text menu"> | ||||
| <div class="header item">{{.i18n.Tr "custom.foot.help"}}</div> | <div class="header item">{{.i18n.Tr "custom.foot.help"}}</div> | ||||
| <div class="ui language bottom floating slide up dropdown link item"> | <div class="ui language bottom floating slide up dropdown link item"> | ||||
| <i class="world icon"></i> | |||||
| <i class="globe icon"></i> | |||||
| <div class="text">{{.LangName}}</div> | <div class="text">{{.LangName}}</div> | ||||
| <div class="menu"> | <div class="menu"> | ||||
| {{range .AllLangs}} | {{range .AllLangs}} | ||||
| @@ -29,12 +29,12 @@ | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <a href="https://git.openi.org.cn/zeizei/OpenI_Learning" class=" item a_margin" target="_blank"><i class="ri-creative-commons-by-line footer_icon" ></i><p class="footer_icon">{{.i18n.Tr "custom.Platform_Tutorial"}}</p> </a> | |||||
| {{if .EnableSwagger}}<a href="/api/swagger" class=" item a_margin"><i class="ri-exchange-line footer_icon" > </i><p class="footer_icon">API</p> </a>{{end}} | |||||
| <a href="https://git.openi.org.cn/zeizei/OpenI_Learning" class="item" target="_blank"><i class="compass icon" ></i> {{.i18n.Tr "custom.Platform_Tutorial"}}</a> | |||||
| {{if .EnableSwagger}}<a href="/api/swagger" class="item"><i class="plug icon"></i> API</a>{{end}} | |||||
| {{if .IsSigned}} | {{if .IsSigned}} | ||||
| <a href="https://git.openi.org.cn/zeizei/OpenI_Learning/issues/new" class=" item a_margin" target="_blank"><i class="ri-mail-send-line footer_icon"></i><p class="footer_icon">{{.i18n.Tr "custom.foot.advice_feedback"}}</p></a> | |||||
| <a href="https://git.openi.org.cn/zeizei/OpenI_Learning/issues/new" class="item" target="_blank"><i class="envelope icon"></i> {{.i18n.Tr "custom.foot.advice_feedback"}}</a> | |||||
| {{else}} | {{else}} | ||||
| <a href="{{AppSubUrl}}/user/login" class=" item a_margin" ><i class="ri-mail-send-line footer_icon" ></i><p class="footer_icon">{{.i18n.Tr "custom.foot.advice_feedback"}}</p></a> | |||||
| <a href="{{AppSubUrl}}/user/login" class="item"><i class="envelope icon"></i> {{.i18n.Tr "custom.foot.advice_feedback"}}</a> | |||||
| {{end}} | {{end}} | ||||
| {{template "custom/extra_links_footer" .}} | {{template "custom/extra_links_footer" .}} | ||||
| @@ -18,7 +18,7 @@ | |||||
| <div class="column ui vertical text menu"> | <div class="column ui vertical text menu"> | ||||
| <div class="header item">{{.i18n.Tr "custom.foot.help"}}</div> | <div class="header item">{{.i18n.Tr "custom.foot.help"}}</div> | ||||
| <div class="ui language bottom floating slide up dropdown link item"> | <div class="ui language bottom floating slide up dropdown link item"> | ||||
| <i class="world icon"></i> | |||||
| <i class="globe icon"></i> | |||||
| <div class="text">{{.LangName}}</div> | <div class="text">{{.LangName}}</div> | ||||
| <div class="menu"> | <div class="menu"> | ||||
| {{range .AllLangs}} | {{range .AllLangs}} | ||||
| @@ -26,12 +26,12 @@ | |||||
| {{end}} | {{end}} | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <a href="https://git.openi.org.cn/zeizei/OpenI_Learning" class=" item a_margin" target="_blank"><i class="ri-creative-commons-by-line footer_icon" ></i><p class="footer_icon">{{.i18n.Tr "custom.Platform_Tutorial"}}</p> </a> | |||||
| {{if .EnableSwagger}}<a href="/api/swagger" class=" item a_margin"><i class="ri-exchange-line footer_icon" > </i><p class="footer_icon">API</p> </a>{{end}} | |||||
| <a href="https://git.openi.org.cn/zeizei/OpenI_Learning" class="item" target="_blank"><i class="compass icon"></i> {{.i18n.Tr "custom.Platform_Tutorial"}} </a> | |||||
| {{if .EnableSwagger}}<a href="/api/swagger" class="item"><i class="plug icon" ></i> API</a>{{end}} | |||||
| {{if .IsSigned}} | {{if .IsSigned}} | ||||
| <a href="https://git.openi.org.cn/zeizei/OpenI_Learning/issues/new" class=" item a_margin" target="_blank"><i class="ri-mail-send-line footer_icon"></i><p class="footer_icon">{{.i18n.Tr "custom.foot.advice_feedback"}}</p></a> | |||||
| <a href="https://git.openi.org.cn/zeizei/OpenI_Learning/issues/new" class="item" target="_blank"><i class="envelope icon"></i> {{.i18n.Tr "custom.foot.advice_feedback"}}</a> | |||||
| {{else}} | {{else}} | ||||
| <a href="{{AppSubUrl}}/user/login" class=" item a_margin" ><i class="ri-mail-send-line footer_icon" ></i><p class="footer_icon footer_icon">{{.i18n.Tr "custom.foot.advice_feedback"}}</p></a> | |||||
| <a href="{{AppSubUrl}}/user/login" class="item"><i class="envelope icon"></i> {{.i18n.Tr "custom.foot.advice_feedback"}}</a> | |||||
| {{end}} | {{end}} | ||||
| {{template "custom/extra_links_footer" .}} | {{template "custom/extra_links_footer" .}} | ||||
| </div> | </div> | ||||
| @@ -0,0 +1,37 @@ | |||||
| <input type="hidden" id="ai_model_version" name="model_version" value="{{$.model_version}}"> | |||||
| <div class="inline min_title fields" style="{{if not .job_name}}width: 96.8%{{else}}width: 94.8%{{end}};"> | |||||
| <label class="{{if not .job_name}}label-fix-width{{end}}" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.infer_job.select_model"}}</label> | |||||
| <div class="six wide field"> | |||||
| <div class="ui fluid search selection dropdown" id="select_model"> | |||||
| <input type="hidden" name="model_name" required value="{{$.model_name}}"> | |||||
| <div class="text"></div> | |||||
| <i class="dropdown icon"></i> | |||||
| <div class="menu" id="model_name"> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div class="three wide field"> | |||||
| <div class="ui fluid search selection dropdown" id="select_model_version"> | |||||
| <input type="hidden" name="pre_train_model_url" value="{{$.pre_train_model_url}}" required> | |||||
| <div class="text"></div> | |||||
| <i class="dropdown icon"></i> | |||||
| <div class="menu" id="model_name_version"> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div class="five wide field"> | |||||
| <div class="ui fluid search selection dropdown" id="select_model_checkpoint"> | |||||
| <input type="hidden" name="ckpt_name" value="{{$.ckpt_name}}" required> | |||||
| <div class="text"></div> | |||||
| <i class="dropdown icon"></i> | |||||
| <div class="menu" id="model_checkpoint"> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <span > | |||||
| <i class="question circle icon" data-content="{{.i18n.Tr "cloudbrain.model_file_postfix_rule"}}" data-position="top center" data-variation="inverted mini"></i> | |||||
| </span> | |||||
| </div> | |||||
| @@ -70,7 +70,7 @@ | |||||
| <div class="repository"> | <div class="repository"> | ||||
| {{template "repo/header" .}} | {{template "repo/header" .}} | ||||
| <div class="ui container"> | <div class="ui container"> | ||||
| <div class="cloudbrain-type" style="display: none;" data-cloudbrain-type="{{.datasetType}}" data-repo-link="{{.RepoLink}}" data-queue="{{.QueuesDetail}}" data-queue-start="{{.i18n.Tr "repo.wait_count_start"}}" data-queue-end="{{.i18n.Tr "repo.wait_count_end"}}"></div> | |||||
| <div class="cloudbrain-type" style="display: none;" data-cloudbrain-type="{{.datasetType}}" data-repo-link="{{.RepoLink}}" data-flag-model="true" data-dataset-uuid="{{.attachment}}" data-dataset-name="{{.dataset_name}}" data-queue="{{.QueuesDetail}}" data-queue-start="{{.i18n.Tr "repo.wait_count_start"}}" data-queue-end="{{.i18n.Tr "repo.wait_count_end"}}"></div> | |||||
| {{template "base/alert" .}} | {{template "base/alert" .}} | ||||
| <h4 class="ui top attached header"> | <h4 class="ui top attached header"> | ||||
| {{.i18n.Tr "repo.modelarts.train_job.new"}} | {{.i18n.Tr "repo.modelarts.train_job.new"}} | ||||
| @@ -125,15 +125,14 @@ | |||||
| <span style="color: #888;font-size: 12px;">{{.i18n.Tr "cloudbrain.new_train_gpu_tooltips" "/code" "/dataset" "/model" | Safe}}</span> | <span style="color: #888;font-size: 12px;">{{.i18n.Tr "cloudbrain.new_train_gpu_tooltips" "/code" "/dataset" "/model" | Safe}}</span> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div class="required min_title inline field"> | |||||
| <div class="required min_title inline field" style="margin-bottom: 0rem !important;"> | |||||
| <label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.job_name"}}</label> | <label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.job_name"}}</label> | ||||
| <input style="width: 60%;" name="display_job_name" id="display_job_name" | <input style="width: 60%;" name="display_job_name" id="display_job_name" | ||||
| placeholder={{.i18n.Tr "repo.modelarts.train_job.job_name"}} value="{{.display_job_name}}" | placeholder={{.i18n.Tr "repo.modelarts.train_job.job_name"}} value="{{.display_job_name}}" | ||||
| tabindex="3" onkeyup="this.value=this.value.replace(/[, ]/g,'')" autofocus required | tabindex="3" onkeyup="this.value=this.value.replace(/[, ]/g,'')" autofocus required | ||||
| maxlength="36"> | maxlength="36"> | ||||
| <span class="tooltips" style="display: block;margin-left: 11.5rem;">{{.i18n.Tr "repo.cloudbrain_jobname_err"}}</span> | |||||
| </div> | </div> | ||||
| <span class="tooltips" style="margin-left: 11.5rem;margin-bottom: 2rem;">{{.i18n.Tr "repo.cloudbrain_jobname_err"}}</span> | |||||
| <div class="inline min_title field"> | <div class="inline min_title field"> | ||||
| <label class="label-fix-width" style="font-weight: normal;" | <label class="label-fix-width" style="font-weight: normal;" | ||||
| for="description">{{.i18n.Tr "repo.modelarts.train_job.description"}}</label> | for="description">{{.i18n.Tr "repo.modelarts.train_job.description"}}</label> | ||||
| @@ -168,7 +167,7 @@ | |||||
| {{end}} | {{end}} | ||||
| </select> | </select> | ||||
| </div> | </div> | ||||
| {{template "custom/select_model" .}} | |||||
| <div class="inline required field" style="display: none;"> | <div class="inline required field" style="display: none;"> | ||||
| <label>{{.i18n.Tr "cloudbrain.task_type"}}</label> | <label>{{.i18n.Tr "cloudbrain.task_type"}}</label> | ||||
| <select id="cloudbrain_job_type" class="ui search dropdown" placeholder="选择任务类型" style='width:385px' | <select id="cloudbrain_job_type" class="ui search dropdown" placeholder="选择任务类型" style='width:385px' | ||||
| @@ -176,28 +175,6 @@ | |||||
| <option name="job_type" value="TRAIN">TRAIN</option> | <option name="job_type" value="TRAIN">TRAIN</option> | ||||
| </select> | </select> | ||||
| </div> | </div> | ||||
| <!--<div class="required min_title inline field"> | |||||
| <label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "cloudbrain.gpu_type"}}</label> | |||||
| <select id="cloudbrain_gpu_type" class="ui search width806 dropdown gpu-type" placeholder="选择GPU类型" | |||||
| style='width:385px' name="gpu_type"> | |||||
| {{if .gpu_type}} | |||||
| {{range .train_gpu_types}} | |||||
| {{if eq $.gpu_type .Queue}} | |||||
| <option value="{{.Queue}}">{{.Value}}</option> | |||||
| {{end}} | |||||
| {{end}} | |||||
| {{range .train_gpu_types}} | |||||
| {{if ne $.gpu_type .Queue}} | |||||
| <option value="{{.Queue}}">{{.Value}}</option> | |||||
| {{end}} | |||||
| {{end}} | |||||
| {{else}} | |||||
| {{range .train_gpu_types}} | |||||
| <option value="{{.Queue}}">{{.Value}}</option> | |||||
| {{end}} | |||||
| {{end}} | |||||
| </select> | |||||
| </div>--> | |||||
| <div id="images-new-cb"> | <div id="images-new-cb"> | ||||
| </div> | </div> | ||||
| @@ -228,33 +205,10 @@ | |||||
| style="margin-left: 0.5rem;cursor:pointer;color: rgba(3, 102, 214, 100);font-size: 14px;line-height: 26px;font-family: SourceHanSansSC-medium;"><i | style="margin-left: 0.5rem;cursor:pointer;color: rgba(3, 102, 214, 100);font-size: 14px;line-height: 26px;font-family: SourceHanSansSC-medium;"><i | ||||
| class="plus square outline icon"></i>{{.i18n.Tr "repo.modelarts.train_job.add_run_parameter"}}</span> | class="plus square outline icon"></i>{{.i18n.Tr "repo.modelarts.train_job.add_run_parameter"}}</span> | ||||
| <input id="store_run_para" type="hidden" name="run_para_list"> | <input id="store_run_para" type="hidden" name="run_para_list"> | ||||
| <div class="dynamic field" style="margin-top: 1rem;" data-params="{{.run_para_list}}"> | |||||
| <div class="dynamic field" style="margin-top: 1rem;" data-params="{{.run_para_list}}" data-params-value="{{.i18n.Tr "repo.modelarts.train_job.parameter_value"}}" data-params-name="{{.i18n.Tr "repo.modelarts.train_job.parameter_name"}}"> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <!--<div class="required min_title inline field"> | |||||
| <label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "cloudbrain.resource_specification"}}</label> | |||||
| <select id="cloudbrain_resource_spec" class="ui search dropdown" placeholder="选择资源规格" | |||||
| style='width:385px' name="resource_spec_id"> | |||||
| {{if .resource_spec_id}} | |||||
| {{range .train_resource_specs}} | |||||
| {{if eq $.resource_spec_id .Id}} | |||||
| <option value="{{.Id}}">{{$.i18n.Tr "cloudbrain.gpu_num"}}:{{.GpuNum}},{{$.i18n.Tr "cloudbrain.cpu_num"}}:{{.CpuNum}},{{$.i18n.Tr "cloudbrain.memory"}}(MB):{{.MemMiB}},{{$.i18n.Tr "cloudbrain.shared_memory"}}(MB):{{.ShareMemMiB}}</option> | |||||
| {{end}} | |||||
| {{end}} | |||||
| {{range .train_resource_specs}} | |||||
| {{if ne $.resource_spec_id .Id}} | |||||
| <option value="{{.Id}}">{{$.i18n.Tr "cloudbrain.gpu_num"}}:{{.GpuNum}},{{$.i18n.Tr "cloudbrain.cpu_num"}}:{{.CpuNum}},{{$.i18n.Tr "cloudbrain.memory"}}(MB):{{.MemMiB}},{{$.i18n.Tr "cloudbrain.shared_memory"}}(MB):{{.ShareMemMiB}}</option> | |||||
| {{end}} | |||||
| {{end}} | |||||
| {{else}} | |||||
| {{range .train_resource_specs}} | |||||
| <option name="resource_spec_id" value="{{.Id}}"> | |||||
| {{$.i18n.Tr "cloudbrain.gpu_num"}}:{{.GpuNum}},{{$.i18n.Tr "cloudbrain.cpu_num"}}:{{.CpuNum}},{{$.i18n.Tr "cloudbrain.memory"}}(MB):{{.MemMiB}},{{$.i18n.Tr "cloudbrain.shared_memory"}}(MB):{{.ShareMemMiB}}</option> | |||||
| {{end}} | |||||
| {{end}} | |||||
| </select> | |||||
| </div>--> | |||||
| <div class="required min_title inline field"> | <div class="required min_title inline field"> | ||||
| <label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "cloudbrain.resource_specification"}}</label> | <label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "cloudbrain.resource_specification"}}</label> | ||||
| @@ -290,166 +244,8 @@ | |||||
| </div> | </div> | ||||
| {{template "base/footer" .}} | {{template "base/footer" .}} | ||||
| <script src="{{StaticUrlPrefix}}/js/specsuse.js?v={{MD5 AppVer}}" type="text/javascript"></script> | <script src="{{StaticUrlPrefix}}/js/specsuse.js?v={{MD5 AppVer}}" type="text/javascript"></script> | ||||
| <script src="{{StaticUrlPrefix}}/js/cloudbrainNew.js?v={{MD5 AppVer}}" type="text/javascript"></script> | |||||
| <script> | <script> | ||||
| let form = document.getElementById('form_id'); | |||||
| let createFlag = false | |||||
| form.onsubmit = function (e) { | |||||
| if(createFlag) return false | |||||
| createFlag = true | |||||
| } | |||||
| $('select.dropdown') | |||||
| .dropdown(); | |||||
| $('.menu .item') | |||||
| .tab(); | |||||
| $(document).keydown(function(event){ | |||||
| switch(event.keyCode){ | |||||
| case 13:return false; | |||||
| } | |||||
| }); | |||||
| $(document).ready(function(){ | |||||
| let params = $('.dynamic.field').data('params') | |||||
| params&¶ms.parameter.forEach((item,index)=>{ | |||||
| Add_parameter(index,flag=true,item) | |||||
| }) | |||||
| }) | |||||
| // 参数增加、删除、修改、保存 | |||||
| function Add_parameter(i,flag=false,paramsObject={}) { | |||||
| let value = '' | |||||
| value += `<div class="two fields width85" id= "para${i}">` | |||||
| value += '<div class="field">' | |||||
| let placeholder_value='{{.i18n.Tr "repo.modelarts.train_job.parameter_value"}}' | |||||
| let placeholder_name='{{.i18n.Tr "repo.modelarts.train_job.parameter_name"}}' | |||||
| if(flag){ | |||||
| value +=`<input type="text" class="shipping_first-name" value="${paramsObject.label}">` | |||||
| }else{ | |||||
| value +='<input type="text" class="shipping_first-name" required placeholder="' + placeholder_name+ '">' | |||||
| } | |||||
| value += '</div>' | |||||
| value += '<div class="field">' | |||||
| if(flag){ | |||||
| value +=`<input type="text" class="shipping_last-name" value="${paramsObject.value}">` | |||||
| }else{ | |||||
| value +='<input type="text" class="shipping_last-name" required placeholder="' + placeholder_value + '">' | |||||
| } | |||||
| value += '</div>' | |||||
| value += '<span><i class="trash icon"></i></span>' | |||||
| value += '</div>' | |||||
| $(".dynamic.field").append(value) | |||||
| } | |||||
| $('#add_run_para').click(function () { | |||||
| var len = $(".dynamic.field .two.fields").length | |||||
| Add_parameter(len) | |||||
| }); | |||||
| $(".dynamic.field").on("click", ".trash.icon", function () { | |||||
| var index = $(this).parent().parent().index() | |||||
| $(this).parent().parent().remove() | |||||
| var len = $(".dynamic.field .two.fields").length | |||||
| $(".dynamic.field .two.fields").each(function () { | |||||
| var cur_index = $(this).index() | |||||
| $(this).attr('id', 'para' + cur_index) | |||||
| }) | |||||
| }); | |||||
| $('.question.circle.icon').hover(function () { | |||||
| $(this).popup('show') | |||||
| }); | |||||
| $('select.dropdown') | |||||
| .dropdown(); | |||||
| var isValidate = false; | |||||
| function validate() { | |||||
| $('.ui.form') | |||||
| .form({ | |||||
| on: 'blur', | |||||
| fields: { | |||||
| boot_file: { | |||||
| identifier: 'boot_file', | |||||
| rules: [ | |||||
| { | |||||
| type: 'regExp[/.+\.py$/g]', | |||||
| } | |||||
| ] | |||||
| }, | |||||
| display_job_name: { | |||||
| identifier: 'display_job_name', | |||||
| rules: [ | |||||
| { | |||||
| type: 'regExp[/^[a-z0-9][a-z0-9-_]{1,34}[a-z0-9-]$/]', | |||||
| } | |||||
| ] | |||||
| }, | |||||
| attachment: { | |||||
| identifier: 'attachment', | |||||
| rules: [ | |||||
| { | |||||
| type: 'empty', | |||||
| } | |||||
| ] | |||||
| }, | |||||
| work_server_number: { | |||||
| identifier: 'work_server_number', | |||||
| rules: [ | |||||
| { | |||||
| type: 'integer[1..25]', | |||||
| } | |||||
| ] | |||||
| }, | |||||
| branch_name: { | |||||
| identifier: 'branch_name', | |||||
| rules: [ | |||||
| { | |||||
| type: 'empty', | |||||
| } | |||||
| ] | |||||
| }, | |||||
| spec_id: { | |||||
| identifier: 'spec_id', | |||||
| rules: [{ type: 'empty' }] | |||||
| } | |||||
| }, | |||||
| onSuccess: function () { | |||||
| // $('.ui.page.dimmer').dimmer('show') | |||||
| document.getElementById("mask").style.display = "block" | |||||
| isValidate = true; | |||||
| }, | |||||
| onFailure: function (e) { | |||||
| isValidate = false; | |||||
| return false; | |||||
| } | |||||
| }) | |||||
| } | |||||
| document.onreadystatechange = function () { | |||||
| if (document.readyState === "complete") { | |||||
| document.getElementById("mask").style.display = "none" | |||||
| } | |||||
| } | |||||
| function send_run_para() { | |||||
| var run_parameters = [] | |||||
| var msg = {} | |||||
| $(".dynamic.field .two.fields").each(function () { | |||||
| var para_name = $(this).find('input.shipping_first-name').val() | |||||
| var para_value = $(this).find('input.shipping_last-name').val() | |||||
| run_parameters.push({ "label": para_name, "value": para_value }) | |||||
| }) | |||||
| msg["parameter"] = run_parameters | |||||
| msg = JSON.stringify(msg) | |||||
| $('#store_run_para').val(msg) | |||||
| } | |||||
| validate(); | |||||
| $('.ui.create_train_job.green.button').click(function (e) { | |||||
| send_run_para(); | |||||
| validate(); | |||||
| }) | |||||
| ;(function() { | ;(function() { | ||||
| var SPECS = {{ .train_specs }}; | var SPECS = {{ .train_specs }}; | ||||
| var showPoint = {{ .CloudBrainPaySwitch }}; | var showPoint = {{ .CloudBrainPaySwitch }}; | ||||
| @@ -251,12 +251,11 @@ | |||||
| <span class="accordion-panel-title-content"> | <span class="accordion-panel-title-content"> | ||||
| <span> | <span> | ||||
| <div style="float: right;"> | <div style="float: right;"> | ||||
| {{if and ($.canDownload) (eq .Status "SUCCEEDED") ($.Permission.CanWrite $.UnitTypeModelManage) }} | |||||
| {{if and ($.canDownload) (ne .Status "WAITING") ($.Permission.CanWrite $.UnitTypeModelManage) }} | |||||
| <a class="ti-action-menu-item" id="{{.VersionName}}-create-model" | <a class="ti-action-menu-item" id="{{.VersionName}}-create-model" | ||||
| onclick="showcreate({{.}})">{{$.i18n.Tr "repo.modelarts.create_model"}}</a> | onclick="showcreate({{.}})">{{$.i18n.Tr "repo.modelarts.create_model"}}</a> | ||||
| {{else}} | {{else}} | ||||
| <a class="ti-action-menu-item disabled" id="{{.VersionName}}-create-model" | |||||
| onclick="showcreate({{.}})">{{$.i18n.Tr "repo.modelarts.create_model"}}</a> | |||||
| <a class="ti-action-menu-item disabled" id="{{.VersionName}}-create-model">{{$.i18n.Tr "repo.modelarts.create_model"}}</a> | |||||
| {{end}} | {{end}} | ||||
| </div> | </div> | ||||
| @@ -632,7 +631,7 @@ | |||||
| <label for="modelSelectedFile">{{.i18n.Tr "repo.model.manage.modelfile"}}</label> | <label for="modelSelectedFile">{{.i18n.Tr "repo.model.manage.modelfile"}}</label> | ||||
| </div> | </div> | ||||
| <div class="thirteen wide field" style="position:relative"> | <div class="thirteen wide field" style="position:relative"> | ||||
| <input id="modelSelectedFile" type="text" readonly required onclick="showMenu();" name="modelSelectedFile" > | |||||
| <input id="modelSelectedFile" type="text" readonly required onclick="showMenu();" name="modelSelectedFile"> | |||||
| <div id="menuContent" class="menuContent" style="display:none;"> | <div id="menuContent" class="menuContent" style="display:none;"> | ||||
| <ul id="treeDemo" class="ztree"></ul> | <ul id="treeDemo" class="ztree"></ul> | ||||
| </div> | </div> | ||||
| @@ -838,6 +837,10 @@ | |||||
| .modal('show') | .modal('show') | ||||
| } | } | ||||
| function createModel() { | function createModel() { | ||||
| if(!$('input#modelSelectedFile').val()){ | |||||
| $('input#modelSelectedFile').parent().addClass('error') | |||||
| return | |||||
| } | |||||
| let url_href = `/${userName}/${repoPath}/modelmanage/create_new_model` | let url_href = `/${userName}/${repoPath}/modelmanage/create_new_model` | ||||
| let data = $("#formId").serialize() | let data = $("#formId").serialize() | ||||
| $("#mask").css({ "display": "block", "z-index": "9999" }) | $("#mask").css({ "display": "block", "z-index": "9999" }) | ||||
| @@ -62,20 +62,20 @@ | |||||
| <div class="repository"> | <div class="repository"> | ||||
| {{template "repo/header" .}} | {{template "repo/header" .}} | ||||
| <div class="ui container"> | <div class="ui container"> | ||||
| <div class="cloudbrain-type" style="display: none;" data-cloudbrain-type="{{.datasetType}}" data-repo-link="{{.RepoLink}}" data-flag-model="true" data-dataset-uuid="{{.attachment}}" data-dataset-name="{{.dataset_name}}"></div> | |||||
| {{template "base/alert" .}} | {{template "base/alert" .}} | ||||
| <h4 class="ui top attached header"> | <h4 class="ui top attached header"> | ||||
| {{.i18n.Tr "repo.modelarts.train_job.new"}} | {{.i18n.Tr "repo.modelarts.train_job.new"}} | ||||
| </h4> | </h4> | ||||
| <div class="ui attached segment"> | <div class="ui attached segment"> | ||||
| <!-- equal width --> | <!-- equal width --> | ||||
| <form id="form_id" class="ui form" action="{{.Link}}" method="post"> | |||||
| <form id="form_id" class="ui form" action="{{.Link}}{{if not .IsCreate}}?compute_resource=CPU/GPU{{end}}" method="post"> | |||||
| {{.CsrfTokenHtml}} | {{.CsrfTokenHtml}} | ||||
| <input type="hidden" name="action" value="update"> | <input type="hidden" name="action" value="update"> | ||||
| <input type="hidden" id="ai_engine_name" name="engine_name" value=""> | <input type="hidden" id="ai_engine_name" name="engine_name" value=""> | ||||
| <input type="hidden" id="ai_flavor_name" name="flavor_name" value=""> | <input type="hidden" id="ai_flavor_name" name="flavor_name" value=""> | ||||
| <input type="hidden" id="ai_image_name" value="{{.image}}"> | <input type="hidden" id="ai_image_name" value="{{.image}}"> | ||||
| <input type="hidden" id="fail_dataset_name" value="{{$.dataset_name}}"> | |||||
| <input type="hidden" id="fail_dataset_uuid" value="{{$.attachment}}"> | |||||
| <h4 class="train-job-title ui header ">{{.i18n.Tr "repo.modelarts.train_job.basic_info"}}:</h4> | <h4 class="train-job-title ui header ">{{.i18n.Tr "repo.modelarts.train_job.basic_info"}}:</h4> | ||||
| <div class="required min_title inline field"> | <div class="required min_title inline field"> | ||||
| <label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "cloudbrain.resource_cluster"}}</label> | <label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "cloudbrain.resource_cluster"}}</label> | ||||
| @@ -116,12 +116,12 @@ | |||||
| <span style="color: #888;font-size: 12px;">{{.i18n.Tr "cloudbrain.new_train_gpu_tooltips" "/tmp/code" "/tmp/dataset" "/tmp/output" | Safe}}</span> | <span style="color: #888;font-size: 12px;">{{.i18n.Tr "cloudbrain.new_train_gpu_tooltips" "/tmp/code" "/tmp/dataset" "/tmp/output" | Safe}}</span> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div class="required min_title inline field"> | |||||
| <div class="required min_title inline field" style="margin-bottom: 0rem !important;"> | |||||
| <label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.job_name"}}</label> | <label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.job_name"}}</label> | ||||
| <input style="width: 60%;" name="display_job_name" id="display_job_name" placeholder={{.i18n.Tr "repo.modelarts.train_job.job_name"}} value="{{.display_job_name}}" tabindex="3" onkeyup="this.value=this.value.replace(/[, ]/g,'')" autofocus required maxlength="36"> | <input style="width: 60%;" name="display_job_name" id="display_job_name" placeholder={{.i18n.Tr "repo.modelarts.train_job.job_name"}} value="{{.display_job_name}}" tabindex="3" onkeyup="this.value=this.value.replace(/[, ]/g,'')" autofocus required maxlength="36"> | ||||
| <span class="tooltips" style="margin-left: 11.5rem;display: block;">{{.i18n.Tr "repo.cloudbrain_jobname_err"}}</span> | |||||
| </div> | </div> | ||||
| <span class="tooltips" style="margin-left: 11.5rem;margin-bottom: 2rem;">{{.i18n.Tr "repo.cloudbrain_jobname_err"}}</span> | |||||
| <div class="min_title inline field"> | <div class="min_title inline field"> | ||||
| <label class="label-fix-width" style="font-weight: normal;" for="description">{{.i18n.Tr "repo.modelarts.train_job.description"}}</label> | <label class="label-fix-width" style="font-weight: normal;" for="description">{{.i18n.Tr "repo.modelarts.train_job.description"}}</label> | ||||
| {{if .description}} | {{if .description}} | ||||
| @@ -155,7 +155,7 @@ | |||||
| {{end}} | {{end}} | ||||
| </select> | </select> | ||||
| </div> | </div> | ||||
| {{template "custom/select_model" .}} | |||||
| <div id="images-new-grampus"> | <div id="images-new-grampus"> | ||||
| </div> | </div> | ||||
| @@ -173,37 +173,19 @@ | |||||
| </div> | </div> | ||||
| {{template "custom/select_dataset_train" .}} | |||||
| <div id="select-multi-dataset"> | |||||
| </div> | |||||
| <span class="tooltips" style="margin-left: 11.5rem;margin-bottom: 1rem;"></span> | <span class="tooltips" style="margin-left: 11.5rem;margin-bottom: 1rem;"></span> | ||||
| <div class="inline min_title field"> | <div class="inline min_title field"> | ||||
| <label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.run_parameter"}}</label> | <label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.run_parameter"}}</label> | ||||
| <span id="add_run_para" style="margin-left: 0.5rem;cursor:pointer;color: rgba(3, 102, 214, 100);font-size: 14px;line-height: 26px;font-family: SourceHanSansSC-medium;"><i class="plus square outline icon"></i>{{.i18n.Tr "repo.modelarts.train_job.add_run_parameter"}}</span> | <span id="add_run_para" style="margin-left: 0.5rem;cursor:pointer;color: rgba(3, 102, 214, 100);font-size: 14px;line-height: 26px;font-family: SourceHanSansSC-medium;"><i class="plus square outline icon"></i>{{.i18n.Tr "repo.modelarts.train_job.add_run_parameter"}}</span> | ||||
| <input id="store_run_para" type="hidden" name="run_para_list"> | <input id="store_run_para" type="hidden" name="run_para_list"> | ||||
| <div class="dynamic field" style="margin-top: 1rem;" data-params="{{.run_para_list}}"> | |||||
| <div class="dynamic field" style="margin-top: 1rem;" data-params="{{.run_para_list}}" data-params-value="{{.i18n.Tr "repo.modelarts.train_job.parameter_value"}}" data-params-name="{{.i18n.Tr "repo.modelarts.train_job.parameter_name"}}"> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <!--<div class="required min_title inline field" id="flavor_name"> | |||||
| <label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.standard"}}</label> | |||||
| <select class="ui dropdown width81" id="trainjob-flavor" style='width:385px' name="flavor"> | |||||
| {{if .flavor}} | |||||
| {{range .flavor_infos}} | |||||
| {{if eq $.flavor .ID}} | |||||
| <option value="{{.ID}}">{{.Name}}</option> | |||||
| {{end}} | |||||
| {{end}} | |||||
| {{range .flavor_infos}} | |||||
| {{if ne $.flavor .ID}} | |||||
| <option value="{{.ID}}">{{.Name}}</option> | |||||
| {{end}} | |||||
| {{end}} | |||||
| {{else}} | |||||
| {{range .flavor_infos}} | |||||
| <option name="flavor" value="{{.ID}}">{{.Name}}</option> | |||||
| {{end}} | |||||
| {{end}} | |||||
| </select> | |||||
| </div>--> | |||||
| <div class="required min_title inline field" id="flavor_name"> | <div class="required min_title inline field" id="flavor_name"> | ||||
| <label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.standard"}}</label> | <label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.standard"}}</label> | ||||
| <select class="ui dropdown width48" id="__specs__" style='width:385px' name="spec_id" ovalue="{{.spec_id}}" {{if .CloudBrainPaySwitch}}blance="{{.PointAccount.Balance}}"{{end}}></select> | <select class="ui dropdown width48" id="__specs__" style='width:385px' name="spec_id" ovalue="{{.spec_id}}" {{if .CloudBrainPaySwitch}}blance="{{.PointAccount.Balance}}"{{end}}></select> | ||||
| @@ -234,172 +216,8 @@ | |||||
| </div> | </div> | ||||
| {{template "base/footer" .}} | {{template "base/footer" .}} | ||||
| <script src="{{StaticUrlPrefix}}/js/specsuse.js?v={{MD5 AppVer}}" type="text/javascript"></script> | <script src="{{StaticUrlPrefix}}/js/specsuse.js?v={{MD5 AppVer}}" type="text/javascript"></script> | ||||
| <script src="{{StaticUrlPrefix}}/js/cloudbrainNew.js?v={{MD5 AppVer}}" type="text/javascript"></script> | |||||
| <script> | <script> | ||||
| let form = document.getElementById('form_id'); | |||||
| let createFlag = false | |||||
| form.onsubmit = function (e) { | |||||
| if(createFlag) return false | |||||
| createFlag = true | |||||
| } | |||||
| $('select.dropdown') | |||||
| .dropdown(); | |||||
| $('.menu .item') | |||||
| .tab(); | |||||
| $(document).ready(function(){ | |||||
| let params = $('.dynamic.field').data('params') | |||||
| params&¶ms.parameter.forEach((item,index)=>{ | |||||
| Add_parameter(index,flag=true,item) | |||||
| }) | |||||
| }) | |||||
| // 参数增加、删除、修改、保存 | |||||
| function Add_parameter(i,flag=false,paramsObject={}) { | |||||
| let value = '' | |||||
| value += `<div class="two fields width85" id= "para${i}">` | |||||
| value += '<div class="field">' | |||||
| let placeholder_value='{{.i18n.Tr "repo.modelarts.train_job.parameter_value"}}' | |||||
| let placeholder_name='{{.i18n.Tr "repo.modelarts.train_job.parameter_name"}}' | |||||
| if(flag){ | |||||
| value +=`<input type="text" class="shipping_first-name" value="${paramsObject.label}">` | |||||
| }else{ | |||||
| value +='<input type="text" class="shipping_first-name" required placeholder="' + placeholder_name+ '">' | |||||
| } | |||||
| value += '</div>' | |||||
| value += '<div class="field">' | |||||
| if(flag){ | |||||
| value +=`<input type="text" class="shipping_last-name" value="${paramsObject.value}">` | |||||
| }else{ | |||||
| value +='<input type="text" class="shipping_last-name" required placeholder="' + placeholder_value+ '">' | |||||
| } | |||||
| value += '</div>' | |||||
| value += '<span><i class="trash icon"></i></span>' | |||||
| value += '</div>' | |||||
| $(".dynamic.field").append(value) | |||||
| } | |||||
| $('#add_run_para').click(function () { | |||||
| var len = $(".dynamic.field .two.fields").length | |||||
| Add_parameter(len) | |||||
| }); | |||||
| $(".dynamic.field").on("click", ".trash.icon", function () { | |||||
| var index = $(this).parent().parent().index() | |||||
| $(this).parent().parent().remove() | |||||
| var len = $(".dynamic.field .two.fields").length | |||||
| $(".dynamic.field .two.fields").each(function () { | |||||
| var cur_index = $(this).index() | |||||
| $(this).attr('id', 'para' + cur_index) | |||||
| }) | |||||
| }); | |||||
| $('.question.circle.icon').hover(function(){ | |||||
| $(this).popup('show') | |||||
| }); | |||||
| $('select.dropdown') | |||||
| .dropdown(); | |||||
| var isValidate = false; | |||||
| function validate(){ | |||||
| $('.ui.form') | |||||
| .form({ | |||||
| on: 'blur', | |||||
| fields: { | |||||
| boot_file: { | |||||
| identifier : 'boot_file', | |||||
| rules: [ | |||||
| { | |||||
| type: 'regExp[/.+\.py$/g]', | |||||
| } | |||||
| ] | |||||
| }, | |||||
| display_job_name:{ | |||||
| identifier : 'display_job_name', | |||||
| rules: [ | |||||
| { | |||||
| type: 'regExp[/^[a-z0-9][a-z0-9-_]{1,34}[a-z0-9-]$/]', | |||||
| } | |||||
| ] | |||||
| }, | |||||
| attachment:{ | |||||
| identifier : 'attachment', | |||||
| rules: [ | |||||
| { | |||||
| type: 'empty', | |||||
| } | |||||
| ] | |||||
| }, | |||||
| flavor:{ | |||||
| identifier : 'flavor', | |||||
| rules: [ | |||||
| { | |||||
| type: 'empty', | |||||
| } | |||||
| ] | |||||
| }, | |||||
| work_server_number: { | |||||
| identifier : 'work_server_number', | |||||
| rules: [ | |||||
| { | |||||
| type : 'integer[1..25]', | |||||
| } | |||||
| ] | |||||
| }, | |||||
| spec_id: { | |||||
| identifier: 'spec_id', | |||||
| rules: [{ type: 'empty' }] | |||||
| } | |||||
| }, | |||||
| onSuccess: function(){ | |||||
| // $('.ui.page.dimmer').dimmer('show') | |||||
| document.getElementById("mask").style.display = "block" | |||||
| isValidate = true; | |||||
| }, | |||||
| onFailure: function(e){ | |||||
| isValidate = false; | |||||
| return false; | |||||
| } | |||||
| }) | |||||
| } | |||||
| document.onreadystatechange = function() { | |||||
| if (document.readyState === "complete") { | |||||
| document.getElementById("mask").style.display = "none" | |||||
| } | |||||
| } | |||||
| function send_run_para() { | |||||
| var run_parameters = [] | |||||
| var msg = {} | |||||
| $(".dynamic.field .two.fields").each(function () { | |||||
| var para_name = $(this).find('input.shipping_first-name').val() | |||||
| var para_value = $(this).find('input.shipping_last-name').val() | |||||
| run_parameters.push({ "label": para_name, "value": para_value }) | |||||
| }) | |||||
| msg["parameter"] = run_parameters | |||||
| msg = JSON.stringify(msg) | |||||
| $('#store_run_para').val(msg) | |||||
| } | |||||
| function get_name(){ | |||||
| let name1=$("#engine_name .text").text() | |||||
| let name2=$("#flavor_name .text").text() | |||||
| $("input#ai_engine_name").val(name1) | |||||
| $("input#ai_flavor_name").val(name2) | |||||
| } | |||||
| validate(); | |||||
| $('.ui.create_train_job.green.button').click(function(e) { | |||||
| get_name() | |||||
| send_run_para() | |||||
| validate(); | |||||
| }) | |||||
| ;(function() { | ;(function() { | ||||
| var SPECS = {{ .Specs }}; | var SPECS = {{ .Specs }}; | ||||
| var showPoint = {{ .CloudBrainPaySwitch }}; | var showPoint = {{ .CloudBrainPaySwitch }}; | ||||
| @@ -57,19 +57,18 @@ | |||||
| <div class="repository"> | <div class="repository"> | ||||
| {{template "repo/header" .}} | {{template "repo/header" .}} | ||||
| <div class="ui container"> | <div class="ui container"> | ||||
| <div class="cloudbrain-type" style="display: none;" data-cloudbrain-type="{{.datasetType}}" data-repo-link="{{.RepoLink}}" data-flag-model="true" data-dataset-uuid="{{.attachment}}" data-dataset-name="{{.dataset_name}}"></div> | |||||
| {{template "base/alert" .}} | {{template "base/alert" .}} | ||||
| <h4 class="ui top attached header"> | <h4 class="ui top attached header"> | ||||
| {{.i18n.Tr "repo.modelarts.train_job.new"}} | {{.i18n.Tr "repo.modelarts.train_job.new"}} | ||||
| </h4> | </h4> | ||||
| <div class="ui attached segment"> | <div class="ui attached segment"> | ||||
| <!-- equal width --> | <!-- equal width --> | ||||
| <form id="form_id" class="ui form" action="{{.Link}}" method="post"> | |||||
| <form id="form_id" class="ui form" action="{{.Link}}{{if not .IsCreate}}?compute_resource=NPU{{end}}" method="post"> | |||||
| {{.CsrfTokenHtml}} | {{.CsrfTokenHtml}} | ||||
| <input type="hidden" name="action" value="update"> | <input type="hidden" name="action" value="update"> | ||||
| <input type="hidden" id="ai_engine_name" name="engine_name" value=""> | <input type="hidden" id="ai_engine_name" name="engine_name" value=""> | ||||
| <input type="hidden" id="ai_flavor_name" name="flavor_name" value=""> | <input type="hidden" id="ai_flavor_name" name="flavor_name" value=""> | ||||
| <input type="hidden" id="fail_dataset_name" value="{{$.dataset_name}}"> | |||||
| <input type="hidden" id="fail_dataset_uuid" value="{{$.attachment}}"> | |||||
| <h4 class="train-job-title ui header ">{{.i18n.Tr "repo.modelarts.train_job.basic_info"}}:</h4> | <h4 class="train-job-title ui header ">{{.i18n.Tr "repo.modelarts.train_job.basic_info"}}:</h4> | ||||
| <div class="required min_title inline field"> | <div class="required min_title inline field"> | ||||
| <label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "cloudbrain.resource_cluster"}}</label> | <label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "cloudbrain.resource_cluster"}}</label> | ||||
| @@ -110,12 +109,11 @@ | |||||
| <span style="color: #888;font-size: 12px;">{{.i18n.Tr "cloudbrain.new_train_gpu_tooltips" "/cache/code" "/cache/dataset" "/cache/output" | Safe}}</span> | <span style="color: #888;font-size: 12px;">{{.i18n.Tr "cloudbrain.new_train_gpu_tooltips" "/cache/code" "/cache/dataset" "/cache/output" | Safe}}</span> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div class="required min_title inline field"> | |||||
| <div class="required min_title inline field" style="margin-bottom: 0rem !important;"> | |||||
| <label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.job_name"}}</label> | <label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.job_name"}}</label> | ||||
| <input style="width: 60%;" name="display_job_name" id="display_job_name" placeholder={{.i18n.Tr "repo.modelarts.train_job.job_name"}} value="{{.display_job_name}}" tabindex="3" onkeyup="this.value=this.value.replace(/[, ]/g,'')" autofocus required maxlength="36"> | <input style="width: 60%;" name="display_job_name" id="display_job_name" placeholder={{.i18n.Tr "repo.modelarts.train_job.job_name"}} value="{{.display_job_name}}" tabindex="3" onkeyup="this.value=this.value.replace(/[, ]/g,'')" autofocus required maxlength="36"> | ||||
| <span class="tooltips" style="display: block;margin-left: 11.5rem;">{{.i18n.Tr "repo.cloudbrain_jobname_err"}}</span> | |||||
| </div> | </div> | ||||
| <span class="tooltips" style="margin-left: 11.5rem;margin-bottom: 2rem;">{{.i18n.Tr "repo.cloudbrain_jobname_err"}}</span> | |||||
| <div class="min_title inline field"> | <div class="min_title inline field"> | ||||
| <label class="label-fix-width" style="font-weight: normal;" for="description">{{.i18n.Tr "repo.modelarts.train_job.description"}}</label> | <label class="label-fix-width" style="font-weight: normal;" for="description">{{.i18n.Tr "repo.modelarts.train_job.description"}}</label> | ||||
| {{if .description}} | {{if .description}} | ||||
| @@ -149,6 +147,7 @@ | |||||
| {{end}} | {{end}} | ||||
| </select> | </select> | ||||
| </div> | </div> | ||||
| {{template "custom/select_model" .}} | |||||
| <div class="required min_title inline field" id="engine_name"> | <div class="required min_title inline field" id="engine_name"> | ||||
| <label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "cloudbrain.mirror"}}</label> | <label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "cloudbrain.mirror"}}</label> | ||||
| <select class="ui dropdown width81" id="trainjob_images" name="image_id"> | <select class="ui dropdown width81" id="trainjob_images" name="image_id"> | ||||
| @@ -184,38 +183,19 @@ | |||||
| <a href="https://git.openi.org.cn/OpenIOSSG/MNIST_Example/src/branch/master/train_for_c2net.py" target="_blank">{{.i18n.Tr "cloudbrain.view_sample"}}</a> | <a href="https://git.openi.org.cn/OpenIOSSG/MNIST_Example/src/branch/master/train_for_c2net.py" target="_blank">{{.i18n.Tr "cloudbrain.view_sample"}}</a> | ||||
| </div> | </div> | ||||
| {{template "custom/select_dataset_train" .}} | |||||
| <div id="select-multi-dataset"> | |||||
| </div> | |||||
| <span class="tooltips" style="margin-left: 11.5rem;margin-bottom: 1rem;"></span> | <span class="tooltips" style="margin-left: 11.5rem;margin-bottom: 1rem;"></span> | ||||
| <div class="inline min_title field"> | <div class="inline min_title field"> | ||||
| <label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.run_parameter"}}</label> | <label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.run_parameter"}}</label> | ||||
| <span id="add_run_para" style="margin-left: 0.5rem;cursor:pointer;color: rgba(3, 102, 214, 100);font-size: 14px;line-height: 26px;font-family: SourceHanSansSC-medium;"><i class="plus square outline icon"></i>{{.i18n.Tr "repo.modelarts.train_job.add_run_parameter"}}</span> | <span id="add_run_para" style="margin-left: 0.5rem;cursor:pointer;color: rgba(3, 102, 214, 100);font-size: 14px;line-height: 26px;font-family: SourceHanSansSC-medium;"><i class="plus square outline icon"></i>{{.i18n.Tr "repo.modelarts.train_job.add_run_parameter"}}</span> | ||||
| <input id="store_run_para" type="hidden" name="run_para_list"> | <input id="store_run_para" type="hidden" name="run_para_list"> | ||||
| <div class="dynamic field" style="margin-top: 1rem;" data-params="{{.run_para_list}}"> | |||||
| <div class="dynamic field" style="margin-top: 1rem;" data-params="{{.run_para_list}}" data-params-value="{{.i18n.Tr "repo.modelarts.train_job.parameter_value"}}" data-params-name="{{.i18n.Tr "repo.modelarts.train_job.parameter_name"}}"> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <!--<div class="required min_title inline field" id="flavor_name"> | |||||
| <label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.standard"}}</label> | |||||
| <select class="ui dropdown width81" id="trainjob-flavor" style='width:385px' name="flavor"> | |||||
| {{if .flavor}} | |||||
| {{range .flavor_infos}} | |||||
| {{if eq $.flavor .ID}} | |||||
| <option value="{{.ID}}">{{.Name}}</option> | |||||
| {{end}} | |||||
| {{end}} | |||||
| {{range .flavor_infos}} | |||||
| {{if ne $.flavor .ID}} | |||||
| <option value="{{.ID}}">{{.Name}}</option> | |||||
| {{end}} | |||||
| {{end}} | |||||
| {{else}} | |||||
| {{range .flavor_infos}} | |||||
| <option name="flavor" value="{{.ID}}">{{.Name}}</option> | |||||
| {{end}} | |||||
| {{end}} | |||||
| </select> | |||||
| </div>--> | |||||
| <div class="required min_title inline field" id="flavor_name"> | <div class="required min_title inline field" id="flavor_name"> | ||||
| <label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.standard"}}</label> | <label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.standard"}}</label> | ||||
| <select class="ui dropdown width48" id="__specs__" style='width:385px' name="spec_id" ovalue="{{.spec_id}}" {{if .CloudBrainPaySwitch}}blance="{{.PointAccount.Balance}}"{{end}}></select> | <select class="ui dropdown width48" id="__specs__" style='width:385px' name="spec_id" ovalue="{{.spec_id}}" {{if .CloudBrainPaySwitch}}blance="{{.PointAccount.Balance}}"{{end}}></select> | ||||
| @@ -260,167 +240,8 @@ | |||||
| </div> | </div> | ||||
| {{template "base/footer" .}} | {{template "base/footer" .}} | ||||
| <script src="{{StaticUrlPrefix}}/js/specsuse.js?v={{MD5 AppVer}}" type="text/javascript"></script> | <script src="{{StaticUrlPrefix}}/js/specsuse.js?v={{MD5 AppVer}}" type="text/javascript"></script> | ||||
| <script src="{{StaticUrlPrefix}}/js/cloudbrainNew.js?v={{MD5 AppVer}}" type="text/javascript"></script> | |||||
| <script> | <script> | ||||
| let form = document.getElementById('form_id'); | |||||
| let createFlag = false | |||||
| form.onsubmit = function (e) { | |||||
| if(createFlag) return false | |||||
| createFlag = true | |||||
| } | |||||
| $('select.dropdown') | |||||
| .dropdown(); | |||||
| $('.menu .item') | |||||
| .tab(); | |||||
| $(document).ready(function(){ | |||||
| let params = $('.dynamic.field').data('params') | |||||
| params&¶ms.parameter.forEach((item,index)=>{ | |||||
| Add_parameter(index,flag=true,item) | |||||
| }) | |||||
| }) | |||||
| // 参数增加、删除、修改、保存 | |||||
| function Add_parameter(i,flag=false,paramsObject={}) { | |||||
| let value = '' | |||||
| value += `<div class="two fields width85" id= "para${i}">` | |||||
| value += '<div class="field">' | |||||
| let placeholder_value='{{.i18n.Tr "repo.modelarts.train_job.parameter_value"}}' | |||||
| let placeholder_name='{{.i18n.Tr "repo.modelarts.train_job.parameter_name"}}' | |||||
| if(flag){ | |||||
| value +=`<input type="text" class="shipping_first-name" value="${paramsObject.label}">` | |||||
| }else{ | |||||
| value +='<input type="text" class="shipping_first-name" required placeholder="' + placeholder_name+ '">' | |||||
| } | |||||
| value += '</div>' | |||||
| value += '<div class="field">' | |||||
| if(flag){ | |||||
| value +=`<input type="text" class="shipping_last-name" value="${paramsObject.value}">` | |||||
| }else{ | |||||
| value +='<input type="text" class="shipping_last-name" required placeholder="' + placeholder_value+ '">' | |||||
| } | |||||
| value += '</div>' | |||||
| value += '<span><i class="trash icon"></i></span>' | |||||
| value += '</div>' | |||||
| $(".dynamic.field").append(value) | |||||
| } | |||||
| $('#add_run_para').click(function () { | |||||
| var len = $(".dynamic.field .two.fields").length | |||||
| Add_parameter(len) | |||||
| }); | |||||
| $(".dynamic.field").on("click", ".trash.icon", function () { | |||||
| var index = $(this).parent().parent().index() | |||||
| $(this).parent().parent().remove() | |||||
| var len = $(".dynamic.field .two.fields").length | |||||
| $(".dynamic.field .two.fields").each(function () { | |||||
| var cur_index = $(this).index() | |||||
| $(this).attr('id', 'para' + cur_index) | |||||
| }) | |||||
| }); | |||||
| $('.question.circle.icon').hover(function(){ | |||||
| $(this).popup('show') | |||||
| }); | |||||
| $('select.dropdown') | |||||
| .dropdown(); | |||||
| var isValidate = false; | |||||
| function validate(){ | |||||
| $('.ui.form') | |||||
| .form({ | |||||
| on: 'blur', | |||||
| fields: { | |||||
| boot_file: { | |||||
| identifier : 'boot_file', | |||||
| rules: [ | |||||
| { | |||||
| type: 'regExp[/.+\.py$/g]', | |||||
| } | |||||
| ] | |||||
| }, | |||||
| display_job_name:{ | |||||
| identifier : 'display_job_name', | |||||
| rules: [ | |||||
| { | |||||
| type: 'regExp[/^[a-z0-9][a-z0-9-_]{1,34}[a-z0-9-]$/]', | |||||
| } | |||||
| ] | |||||
| }, | |||||
| attachment:{ | |||||
| identifier : 'attachment', | |||||
| rules: [ | |||||
| { | |||||
| type: 'empty', | |||||
| } | |||||
| ] | |||||
| }, | |||||
| work_server_number: { | |||||
| identifier : 'work_server_number', | |||||
| rules: [ | |||||
| { | |||||
| type : 'integer[1..25]', | |||||
| } | |||||
| ] | |||||
| }, | |||||
| spec_id: { | |||||
| identifier: 'spec_id', | |||||
| rules: [{ type: 'empty' }] | |||||
| } | |||||
| }, | |||||
| onSuccess: function(){ | |||||
| // $('.ui.page.dimmer').dimmer('show') | |||||
| document.getElementById("mask").style.display = "block" | |||||
| isValidate = true; | |||||
| }, | |||||
| onFailure: function(e){ | |||||
| isValidate = false; | |||||
| return false; | |||||
| } | |||||
| }) | |||||
| } | |||||
| document.onreadystatechange = function() { | |||||
| if (document.readyState === "complete") { | |||||
| document.getElementById("mask").style.display = "none" | |||||
| } | |||||
| } | |||||
| function send_run_para() { | |||||
| var run_parameters = [] | |||||
| var msg = {} | |||||
| $(".dynamic.field .two.fields").each(function () { | |||||
| var para_name = $(this).find('input.shipping_first-name').val() | |||||
| var para_value = $(this).find('input.shipping_last-name').val() | |||||
| run_parameters.push({ "label": para_name, "value": para_value }) | |||||
| }) | |||||
| msg["parameter"] = run_parameters | |||||
| msg = JSON.stringify(msg) | |||||
| $('#store_run_para').val(msg) | |||||
| } | |||||
| function get_name(){ | |||||
| let name1=$("#engine_name .text").text() | |||||
| let name2=$("#flavor_name .text").text() | |||||
| $("input#ai_engine_name").val(name1) | |||||
| $("input#ai_flavor_name").val(name2) | |||||
| let val_server_num_select = $("#trainjob_work_server_num_select .text").text() | |||||
| // console.log("val_server_num_select:",val_server_num_select) | |||||
| $("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(); | |||||
| }) | |||||
| ;(function() { | ;(function() { | ||||
| var SPECS = {{ .Specs }}; | var SPECS = {{ .Specs }}; | ||||
| var showPoint = {{ .CloudBrainPaySwitch }}; | var showPoint = {{ .CloudBrainPaySwitch }}; | ||||
| @@ -263,12 +263,11 @@ | |||||
| </div> | </div> | ||||
| <div style="float: right;"> | <div style="float: right;"> | ||||
| {{if and ($.canDownload) (eq .Status "SUCCEEDED") ($.Permission.CanWrite $.UnitTypeModelManage) }} | |||||
| {{if and ($.canDownload) (ne .Status "WAITING") ($.Permission.CanWrite $.UnitTypeModelManage) }} | |||||
| <a class="ti-action-menu-item" id="{{.VersionName}}-create-model" | <a class="ti-action-menu-item" id="{{.VersionName}}-create-model" | ||||
| onclick="showcreate({{.}})">{{$.i18n.Tr "repo.modelarts.create_model"}}</a> | onclick="showcreate({{.}})">{{$.i18n.Tr "repo.modelarts.create_model"}}</a> | ||||
| {{else}} | {{else}} | ||||
| <a class="ti-action-menu-item disabled" id="{{.VersionName}}-create-model" | |||||
| onclick="showcreate({{.}})">{{$.i18n.Tr "repo.modelarts.create_model"}}</a> | |||||
| <a class="ti-action-menu-item disabled" id="{{.VersionName}}-create-model">{{$.i18n.Tr "repo.modelarts.create_model"}}</a> | |||||
| {{end}} | {{end}} | ||||
| </div> | </div> | ||||
| @@ -841,6 +840,11 @@ | |||||
| .modal('show') | .modal('show') | ||||
| } | } | ||||
| function createModel() { | function createModel() { | ||||
| if(!$('input#modelSelectedFile').val()){ | |||||
| $('input#modelSelectedFile').parent().addClass('error') | |||||
| return | |||||
| } | |||||
| let url_href = `/${userName}/${repoPath}/modelmanage/create_new_model` | let url_href = `/${userName}/${repoPath}/modelmanage/create_new_model` | ||||
| let data = $("#formId").serialize() | let data = $("#formId").serialize() | ||||
| $("#mask").css({ "display": "block", "z-index": "9999" }) | $("#mask").css({ "display": "block", "z-index": "9999" }) | ||||
| @@ -109,7 +109,6 @@ | |||||
| {{range .Tasks}} | {{range .Tasks}} | ||||
| <div class="ui grid stackable item"> | <div class="ui grid stackable item"> | ||||
| <div class="row"> | <div class="row"> | ||||
| <!-- 任务名 --> | <!-- 任务名 --> | ||||
| <div class="three wide column padding0"> | <div class="three wide column padding0"> | ||||
| <a class="title" href='{{if eq .Cloudbrain.Type 1 }}{{$.Link}}/{{.JobID}}{{else if eq .Cloudbrain.Type 0}}{{$.RepoLink}}/cloudbrain/train-job/{{.JobID}}{{else if eq .Cloudbrain.Type 2}}{{$.RepoLink}}/grampus/train-job/{{.JobID}}{{end}}' title="{{.DisplayJobName}}" style="font-size: 14px;"> | <a class="title" href='{{if eq .Cloudbrain.Type 1 }}{{$.Link}}/{{.JobID}}{{else if eq .Cloudbrain.Type 0}}{{$.RepoLink}}/cloudbrain/train-job/{{.JobID}}{{else if eq .Cloudbrain.Type 2}}{{$.RepoLink}}/grampus/train-job/{{.JobID}}{{end}}' title="{{.DisplayJobName}}" style="font-size: 14px;"> | ||||
| @@ -168,6 +167,21 @@ | |||||
| </a> | </a> | ||||
| {{end}} | {{end}} | ||||
| </div> | |||||
| <!-- 修改任务 --> | |||||
| <div class="ui compact buttons"> | |||||
| {{$.CsrfTokenHtml}} | |||||
| {{if .CanModify}} | |||||
| <a style="padding: 0.5rem 1rem;" class="ui basic blue button" href="{{if eq .Cloudbrain.Type 1}}{{$.Link}}/{{.JobID}}{{else if eq .Cloudbrain.Type 0}}{{$.RepoLink}}/cloudbrain/train-job/{{.JobID}}{{else if eq .Cloudbrain.Type 2}}{{$.RepoLink}}/grampus/train-job/{{.JobID}}{{end}}/create_version{{if .VersionName}}?version_name={{.VersionName}}{{end}}"> | |||||
| {{$.i18n.Tr "repo.modelarts.modify"}} | |||||
| </a> | |||||
| {{else}} | |||||
| <a class="ui basic disabled button"> | |||||
| {{$.i18n.Tr "repo.modelarts.modify"}} | |||||
| </a> | |||||
| {{end}} | |||||
| </div> | </div> | ||||
| <!-- 删除任务 --> | <!-- 删除任务 --> | ||||
| <form class="ui compact buttons" id="delForm-{{.JobID}}" action='{{if eq .Cloudbrain.Type 1}}{{$.Link}}/{{.JobID}}{{else if eq .Cloudbrain.Type 0}}{{$.RepoLink}}/cloudbrain/train-job/{{.JobID}}{{else if eq .Cloudbrain.Type 2}}{{$.RepoLink}}/grampus/train-job/{{.JobID}}{{end}}/del' method="post"> | <form class="ui compact buttons" id="delForm-{{.JobID}}" action='{{if eq .Cloudbrain.Type 1}}{{$.Link}}/{{.JobID}}{{else if eq .Cloudbrain.Type 0}}{{$.RepoLink}}/cloudbrain/train-job/{{.JobID}}{{else if eq .Cloudbrain.Type 2}}{{$.RepoLink}}/grampus/train-job/{{.JobID}}{{end}}/del' method="post"> | ||||
| @@ -62,7 +62,7 @@ | |||||
| <div class="repository"> | <div class="repository"> | ||||
| {{template "repo/header" .}} | {{template "repo/header" .}} | ||||
| <div class="ui container"> | <div class="ui container"> | ||||
| <div class="cloudbrain-type" style="display: none;" data-cloudbrain-type="{{.datasetType}}" data-repo-link="{{.RepoLink}}"></div> | |||||
| <div class="cloudbrain-type" style="display: none;" data-cloudbrain-type="{{.datasetType}}" data-repo-link="{{.RepoLink}}" data-flag-model="true" data-dataset-uuid="{{.attachment}}" data-dataset-name="{{.dataset_name}}"></div> | |||||
| {{template "base/alert" .}} | {{template "base/alert" .}} | ||||
| <h4 class="ui top attached header"> | <h4 class="ui top attached header"> | ||||
| {{.i18n.Tr "repo.modelarts.train_job.new"}} | {{.i18n.Tr "repo.modelarts.train_job.new"}} | ||||
| @@ -119,11 +119,11 @@ | |||||
| <span style="color: #888;font-size: 12px;">{{.i18n.Tr "cloudbrain.train_dataset_path_rule" | Safe}}</span> | <span style="color: #888;font-size: 12px;">{{.i18n.Tr "cloudbrain.train_dataset_path_rule" | Safe}}</span> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div class="required inline min_title field"> | |||||
| <div class="required inline min_title field" style="margin-bottom: 0rem !important;"> | |||||
| <label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.job_name"}}</label> | <label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.job_name"}}</label> | ||||
| <input style="width: 60%;" name="display_job_name" id="display_job_name" placeholder={{.i18n.Tr "repo.modelarts.train_job.job_name"}} value="{{.display_job_name}}" tabindex="3" onkeyup="this.value=this.value.replace(/[, ]/g,'')" autofocus required maxlength="36"> | <input style="width: 60%;" name="display_job_name" id="display_job_name" placeholder={{.i18n.Tr "repo.modelarts.train_job.job_name"}} value="{{.display_job_name}}" tabindex="3" onkeyup="this.value=this.value.replace(/[, ]/g,'')" autofocus required maxlength="36"> | ||||
| </div> | </div> | ||||
| <span class="tooltips" style="margin-left: 11.5rem;margin-bottom: 2rem;">{{.i18n.Tr "repo.cloudbrain_jobname_err"}}</span> | |||||
| <div class="inline min_title field"> | <div class="inline min_title field"> | ||||
| <label class="label-fix-width" style="font-weight: normal;" for="description">{{.i18n.Tr "repo.modelarts.train_job.description"}}</label> | <label class="label-fix-width" style="font-weight: normal;" for="description">{{.i18n.Tr "repo.modelarts.train_job.description"}}</label> | ||||
| {{if .description}} | {{if .description}} | ||||
| @@ -157,8 +157,8 @@ | |||||
| {{end}} | {{end}} | ||||
| </select> | </select> | ||||
| </div> | </div> | ||||
| {{template "custom/select_model" .}} | |||||
| <div class="required inline min_title fields" style="width: 95%;"> | <div class="required inline min_title fields" style="width: 95%;"> | ||||
| <label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.AI_driver"}}</label> | <label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.AI_driver"}}</label> | ||||
| @@ -215,23 +215,7 @@ | |||||
| <label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.run_parameter"}}</label> | <label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.run_parameter"}}</label> | ||||
| <span id="add_run_para" style="margin-left: 0.5rem;cursor:pointer;color: rgba(3, 102, 214, 100);font-size: 14px;line-height: 26px;font-family: SourceHanSansSC-medium;"><i class="plus square outline icon"></i>{{.i18n.Tr "repo.modelarts.train_job.add_run_parameter"}}</span> | <span id="add_run_para" style="margin-left: 0.5rem;cursor:pointer;color: rgba(3, 102, 214, 100);font-size: 14px;line-height: 26px;font-family: SourceHanSansSC-medium;"><i class="plus square outline icon"></i>{{.i18n.Tr "repo.modelarts.train_job.add_run_parameter"}}</span> | ||||
| <input id="store_run_para" type="hidden" name="run_para_list"> | <input id="store_run_para" type="hidden" name="run_para_list"> | ||||
| <div class="dynamic field" style="margin-top: 1rem;"> | |||||
| {{if ne 0 (len .params)}} | |||||
| {{range $k ,$v := .params}} | |||||
| <div class="two fields width85" id="para{{$k}}"> | |||||
| <div class="field"> | |||||
| <input type="text" name="shipping_first-name" value={{$v.Label}} required> | |||||
| </div> | |||||
| <div class="field"> | |||||
| <input type="text" name="shipping_last-name" value={{$v.Value}} required> | |||||
| </div> | |||||
| <span> | |||||
| <i class="trash icon"></i> | |||||
| </span> | |||||
| </div> | |||||
| {{end}} | |||||
| {{end}} | |||||
| <div class="dynamic field" style="margin-top: 1rem;" data-params="{{.run_para_list}}" data-params-value="{{.i18n.Tr "repo.modelarts.train_job.parameter_value"}}" data-params-name="{{.i18n.Tr "repo.modelarts.train_job.parameter_name"}}"> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| @@ -260,27 +244,6 @@ | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <!--<div class="required inline min_title field" id="flaver_name"> | |||||
| <label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.standard"}}</label> | |||||
| <select class="ui dropdown width48" id="trainjob-flavor" name="flavor"> | |||||
| {{if .flavor}} | |||||
| {{range .flavor_infos}} | |||||
| {{if eq $.flavor .Code}} | |||||
| <option value="{{.Code}}">{{.Value}}</option> | |||||
| {{end}} | |||||
| {{end}} | |||||
| {{range .flavor_infos}} | |||||
| {{if ne $.flavor .Code}} | |||||
| <option value="{{.Code}}">{{.Value}}</option> | |||||
| {{end}} | |||||
| {{end}} | |||||
| {{else}} | |||||
| {{range .flavor_infos}} | |||||
| <option name="flavor" value="{{.Code}}">{{.Value}}</option> | |||||
| {{end}} | |||||
| {{end}} | |||||
| </select> | |||||
| </div>--> | |||||
| <div class="required inline min_title field" id="flaver_name"> | <div class="required inline min_title field" id="flaver_name"> | ||||
| <label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.standard"}}</label> | <label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.standard"}}</label> | ||||
| <select class="ui dropdown width48" id="__specs__" name="spec_id" ovalue="{{.spec_id}}" {{if .CloudBrainPaySwitch}}blance="{{.PointAccount.Balance}}"{{end}}></select> | <select class="ui dropdown width48" id="__specs__" name="spec_id" ovalue="{{.spec_id}}" {{if .CloudBrainPaySwitch}}blance="{{.PointAccount.Balance}}"{{end}}></select> | ||||
| @@ -332,7 +295,7 @@ | |||||
| <button class="ui create_train_job green button"> | <button class="ui create_train_job green button"> | ||||
| {{.i18n.Tr "repo.cloudbrain.new"}} | {{.i18n.Tr "repo.cloudbrain.new"}} | ||||
| </button> | </button> | ||||
| <a class="ui button" href="/">{{.i18n.Tr "repo.cloudbrain.cancel"}}</a> | |||||
| <a class="ui button" href="{{.RepoLink}}/modelarts/train-job">{{.i18n.Tr "repo.cloudbrain.cancel"}}</a> | |||||
| </div> | </div> | ||||
| <!-- 模态框 --> | <!-- 模态框 --> | ||||
| @@ -343,226 +306,8 @@ | |||||
| </div> | </div> | ||||
| {{template "base/footer" .}} | {{template "base/footer" .}} | ||||
| <script src="{{StaticUrlPrefix}}/js/specsuse.js?v={{MD5 AppVer}}" type="text/javascript"></script> | <script src="{{StaticUrlPrefix}}/js/specsuse.js?v={{MD5 AppVer}}" type="text/javascript"></script> | ||||
| <script src="{{StaticUrlPrefix}}/js/cloudbrainNew.js?v={{MD5 AppVer}}" type="text/javascript"></script> | |||||
| <script> | <script> | ||||
| let form = document.getElementById('form_id'); | |||||
| let createFlag = false | |||||
| form.onsubmit = function (e) { | |||||
| if(createFlag) return false | |||||
| createFlag = true | |||||
| } | |||||
| let url_href = window.location.pathname.split('create')[0] | |||||
| $(".ui.button").attr('href', url_href) | |||||
| $('select.dropdown') | |||||
| .dropdown(); | |||||
| $('.menu .item') | |||||
| .tab(); | |||||
| $(document).keydown(function(event){ | |||||
| switch(event.keyCode){ | |||||
| case 13:return false; | |||||
| } | |||||
| }); | |||||
| // 参数增加、删除、修改、保存 | |||||
| function Add_parameter(i) { | |||||
| let placeholder_value='{{.i18n.Tr "repo.modelarts.train_job.parameter_value"}}' | |||||
| let placeholder_name='{{.i18n.Tr "repo.modelarts.train_job.parameter_name"}}' | |||||
| value = '<div class="two fields width85" id= "para' + i + '">' + | |||||
| '<div class="field">' + | |||||
| '<input type="text" name="shipping_first-name" required placeholder="' + placeholder_name+ '">' + | |||||
| '</div> ' + | |||||
| '<div class="field"> ' + | |||||
| '<input type="text" name="shipping_last-name" required placeholder="' + placeholder_value+ '">' + | |||||
| '</div>' + | |||||
| '<span>' + | |||||
| '<i class="trash icon">' + | |||||
| '</i>' + | |||||
| '</span>' + | |||||
| '</div>' | |||||
| $(".dynamic.field").append(value) | |||||
| } | |||||
| $('#add_run_para').click(function () { | |||||
| var len = $(".dynamic.field .two.fields").length | |||||
| Add_parameter(len) | |||||
| }); | |||||
| $(".dynamic.field").on("click", ".trash.icon", function () { | |||||
| var index = $(this).parent().parent().index() | |||||
| $(this).parent().parent().remove() | |||||
| var len = $(".dynamic.field .two.fields").length | |||||
| $(".dynamic.field .two.fields").each(function () { | |||||
| var cur_index = $(this).index() | |||||
| $(this).attr('id', 'para' + cur_index) | |||||
| }) | |||||
| }); | |||||
| $('.ui.parameter.green.button').click(function () { | |||||
| var parameters = []; | |||||
| $('table tr').each(function () { | |||||
| $(this).find('td:eq(1)').each(function () { | |||||
| parameters.push($(this).text()); | |||||
| }) | |||||
| $(this).find('input').each(function () { | |||||
| parameters.push($(this).text()) | |||||
| }) | |||||
| }); | |||||
| $('.ui.parameter.modal') | |||||
| .modal('hide'); | |||||
| for (var i = 2; i < parameters.length; i++) { | |||||
| switch (i) { | |||||
| // 数据集uuid待完成 | |||||
| // case (2): | |||||
| // console.log(1) | |||||
| // break; | |||||
| // $("#trainjob_datasets").val(parameters[i]); | |||||
| // console.log($("#trainjob_datasets").val()) | |||||
| case (3): | |||||
| $("input[name='boot_file']").val(parameters[i]); | |||||
| break; | |||||
| case (4): | |||||
| var para = parameters[i].split(" ") | |||||
| for (var j = 0; j < para.length; j++) { | |||||
| var para_name = para[j].split('=')[0] | |||||
| var para_value = para[j].split('=')[1] | |||||
| var len = $(".dynamic.field .two.fields").length | |||||
| Add_parameter(len) | |||||
| var pid = 'para' + len | |||||
| $(".dynamic.field" + " #" + pid + "").find("input[name=shipping_first-name]").val(para_name) | |||||
| $(".dynamic.field" + " #" + pid + "").find("input[name=shipping_last-name]").val(para_value) | |||||
| } | |||||
| break; | |||||
| // 数据集pool_id待完成 | |||||
| // case (5): | |||||
| // $("select[name='pool_id']").val(parameters[i]); | |||||
| // break; | |||||
| case (6): | |||||
| // $("input[name='work_server_number']").val(parameters[i]); | |||||
| break; | |||||
| } | |||||
| } | |||||
| }) | |||||
| $('.ui.save.checkbox').click(function () { | |||||
| $(this).checkbox({ | |||||
| onChange: function () { | |||||
| if ($('.ui.save.checkbox').checkbox('is checked')) { | |||||
| $('#save_para').removeClass("disabled") | |||||
| } else { | |||||
| $('#save_para').addClass("disabled") | |||||
| } | |||||
| } | |||||
| }); | |||||
| }) | |||||
| $('.question.circle.icon').hover(function () { | |||||
| $(this).popup('show') | |||||
| }); | |||||
| $(".item.active.parameter_config").click(function () { | |||||
| $('.ui.parameter.modal') | |||||
| .modal('setting', 'closable', false) | |||||
| .modal('show'); | |||||
| }) | |||||
| $('.ui.deny.button').click(function () { | |||||
| $('.ui.parameter.modal') | |||||
| .modal('hide'); | |||||
| }) | |||||
| $('select.dropdown') | |||||
| .dropdown(); | |||||
| var isValidate = false; | |||||
| function validate() { | |||||
| $('.ui.form') | |||||
| .form({ | |||||
| on: 'blur', | |||||
| fields: { | |||||
| boot_file: { | |||||
| identifier: 'boot_file', | |||||
| rules: [ | |||||
| { | |||||
| type: 'regExp[/.+\.py$/g]', | |||||
| } | |||||
| ] | |||||
| }, | |||||
| display_job_name: { | |||||
| identifier: 'display_job_name', | |||||
| rules: [ | |||||
| { | |||||
| type: 'regExp[/^[a-z0-9][a-z0-9-_]{1,34}[a-z0-9-]$/]', | |||||
| } | |||||
| ] | |||||
| }, | |||||
| attachment: { | |||||
| identifier: 'attachment', | |||||
| rules: [ | |||||
| { | |||||
| type: 'empty', | |||||
| } | |||||
| ] | |||||
| }, | |||||
| work_server_number: { | |||||
| identifier: 'work_server_number', | |||||
| rules: [ | |||||
| { | |||||
| type: 'integer[1..25]', | |||||
| } | |||||
| ] | |||||
| }, | |||||
| spec_id: { | |||||
| identifier: 'spec_id', | |||||
| rules: [{ type: 'empty' }] | |||||
| } | |||||
| }, | |||||
| onSuccess: function () { | |||||
| // $('.ui.page.dimmer').dimmer('show') | |||||
| document.getElementById("mask").style.display = "block" | |||||
| isValidate = true; | |||||
| }, | |||||
| onFailure: function (e) { | |||||
| isValidate = false; | |||||
| return false; | |||||
| } | |||||
| }) | |||||
| } | |||||
| document.onreadystatechange = function () { | |||||
| if (document.readyState === "complete") { | |||||
| document.getElementById("mask").style.display = "none" | |||||
| } | |||||
| } | |||||
| function send_run_para() { | |||||
| var run_parameters = [] | |||||
| var msg = {} | |||||
| $(".dynamic.field .two.fields").each(function () { | |||||
| var para_name = $(this).find('input[name=shipping_first-name]').val() | |||||
| var para_value = $(this).find('input[name=shipping_last-name]').val() | |||||
| run_parameters.push({ "label": para_name, "value": para_value }) | |||||
| }) | |||||
| msg["parameter"] = run_parameters | |||||
| msg = JSON.stringify(msg) | |||||
| $('#store_run_para').val(msg) | |||||
| } | |||||
| function get_name() { | |||||
| let name1 = $("#engine_name .text").text() | |||||
| let name2 = $("#flaver_name .text").text() | |||||
| $("input#ai_engine_name").val(name1) | |||||
| $("input#ai_flaver_name").val(name2) | |||||
| let val_server_num_select = $("#trainjob_work_server_num_select .text").text() | |||||
| // console.log("val_server_num_select:",val_server_num_select) | |||||
| $("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(); | |||||
| }) | |||||
| ;(function() { | ;(function() { | ||||
| var SPECS = {{ .Specs }}; | var SPECS = {{ .Specs }}; | ||||
| var showPoint = {{ .CloudBrainPaySwitch }}; | var showPoint = {{ .CloudBrainPaySwitch }}; | ||||
| @@ -247,12 +247,11 @@ | |||||
| <span> | <span> | ||||
| <div style="float: right;"> | <div style="float: right;"> | ||||
| {{$.CsrfTokenHtml}} | {{$.CsrfTokenHtml}} | ||||
| {{if and (.CanModify) (eq .Status "COMPLETED") ($.Permission.CanWrite $.UnitTypeModelManage) }} | |||||
| {{if and (.CanModify) (ne .Status "WAITING") ($.Permission.CanWrite $.UnitTypeModelManage) }} | |||||
| <a class="ti-action-menu-item" id="{{.VersionName}}-create-model" | <a class="ti-action-menu-item" id="{{.VersionName}}-create-model" | ||||
| onclick="showcreate({{.}})">{{$.i18n.Tr "repo.modelarts.create_model"}}</a> | onclick="showcreate({{.}})">{{$.i18n.Tr "repo.modelarts.create_model"}}</a> | ||||
| {{else}} | {{else}} | ||||
| <a class="ti-action-menu-item disabled" id="{{.VersionName}}-create-model" | |||||
| onclick="showcreate({{.}})">{{$.i18n.Tr "repo.modelarts.create_model"}}</a> | |||||
| <a class="ti-action-menu-item disabled" id="{{.VersionName}}-create-model">{{$.i18n.Tr "repo.modelarts.create_model"}}</a> | |||||
| {{end}} | {{end}} | ||||
| {{if .CanModify}} | {{if .CanModify}} | ||||
| @@ -892,6 +891,10 @@ | |||||
| .modal('show') | .modal('show') | ||||
| } | } | ||||
| function createModel() { | function createModel() { | ||||
| if(!$('input#modelSelectedFile').val()){ | |||||
| $('input#modelSelectedFile').parent().addClass('error') | |||||
| return | |||||
| } | |||||
| let url_href = `/${userName}/${repoPath}/modelmanage/create_new_model` | let url_href = `/${userName}/${repoPath}/modelmanage/create_new_model` | ||||
| let data = $("#formId").serialize() | let data = $("#formId").serialize() | ||||
| $("#mask").css({ "display": "block", "z-index": "9999" }) | $("#mask").css({ "display": "block", "z-index": "9999" }) | ||||
| @@ -55,14 +55,14 @@ | |||||
| <div class="repository"> | <div class="repository"> | ||||
| {{template "repo/header" .}} | {{template "repo/header" .}} | ||||
| <div class="ui container"> | <div class="ui container"> | ||||
| <div class="cloudbrain-type" style="display: none;" data-cloudbrain-type="{{.datasetType}}" data-repo-link="{{.RepoLink}}" data-dataset-uuid="{{.uuid}}" data-dataset-name="{{.dataset_name}}"></div> | |||||
| <div class="cloudbrain-type" style="display: none;" data-cloudbrain-type="{{.datasetType}}" data-repo-link="{{.RepoLink}}" data-flag-model="true" data-dataset-uuid="{{.attachment}}" data-dataset-name="{{.dataset_name}}"></div> | |||||
| {{template "base/alert" .}} | {{template "base/alert" .}} | ||||
| <h4 class="ui top attached header"> | <h4 class="ui top attached header"> | ||||
| {{.i18n.Tr "repo.modelarts.train_job.new"}} | {{.i18n.Tr "repo.modelarts.train_job.new"}} | ||||
| </h4> | </h4> | ||||
| <div class="ui attached segment"> | <div class="ui attached segment"> | ||||
| <!-- equal width --> | <!-- equal width --> | ||||
| <form class="ui form" action="{{$.RepoLink}}/modelarts/train-job/{{.JobID}}/create_version" method="post"> | |||||
| <form id="form_id" class="ui form" action="{{$.RepoLink}}/modelarts/train-job/{{.JobID}}/create_version" method="post"> | |||||
| {{.CsrfTokenHtml}} | {{.CsrfTokenHtml}} | ||||
| <input type="hidden" name="action" value="update"> | <input type="hidden" name="action" value="update"> | ||||
| {{if .version_name}} | {{if .version_name}} | ||||
| @@ -154,7 +154,7 @@ | |||||
| </div> | </div> | ||||
| {{template "custom/select_model" .}} | |||||
| <div class="required unite min_title inline fields" style="width: 90%;"> | <div class="required unite min_title inline fields" style="width: 90%;"> | ||||
| <label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.AI_driver"}} </label> | <label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.AI_driver"}} </label> | ||||
| @@ -202,23 +202,8 @@ | |||||
| <label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.run_parameter"}}</label> | <label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.run_parameter"}}</label> | ||||
| <span id="add_run_para" style="margin-left: 0.5rem;cursor:pointer;color: rgba(3, 102, 214, 100);font-size: 14px;line-height: 26px;font-family: SourceHanSansSC-medium;"><i class="plus square outline icon"></i>{{.i18n.Tr "repo.modelarts.train_job.add_run_parameter"}}</span> | <span id="add_run_para" style="margin-left: 0.5rem;cursor:pointer;color: rgba(3, 102, 214, 100);font-size: 14px;line-height: 26px;font-family: SourceHanSansSC-medium;"><i class="plus square outline icon"></i>{{.i18n.Tr "repo.modelarts.train_job.add_run_parameter"}}</span> | ||||
| <input id="store_run_para" type="hidden" name="run_para_list"> | <input id="store_run_para" type="hidden" name="run_para_list"> | ||||
| <div class="dynamic field" style="margin-top: 1rem;"> | |||||
| {{if ne 0 (len .params)}} | |||||
| {{range $k ,$v := .params}} | |||||
| <div class="two fields width85" id="para{{$k}}"> | |||||
| <div class="field"> | |||||
| <input type="text" name="shipping_first-name" value={{$v.Label}} required> | |||||
| </div> | |||||
| <div class="field"> | |||||
| <input type="text" name="shipping_last-name" value={{$v.Value}} required> | |||||
| </div> | |||||
| <span> | |||||
| <i class="trash icon"></i> | |||||
| </span> | |||||
| </div> | |||||
| {{end}} | |||||
| {{end}} | |||||
| <div class="dynamic field" style="margin-top: 1rem;" data-params="{{.run_para_list}}" data-params-value="{{.i18n.Tr "repo.modelarts.train_job.parameter_value"}}" data-params-name="{{.i18n.Tr "repo.modelarts.train_job.parameter_name"}}"> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| @@ -248,19 +233,6 @@ | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <!--<div class="required unite min_title inline field" id="flaver_name"> | |||||
| <label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.standard"}}</label> | |||||
| <select class="ui dropdown width81" id="trainjob-flavor" style='width:385px' name="flavor"> | |||||
| {{if .flavor_name}} | |||||
| <option name="flavor" value="{{.flavor_code}}">{{.flavor_name}}</option> | |||||
| {{end}} | |||||
| {{range .flavor_infos}} | |||||
| {{if ne $.flavor_code .Code}} | |||||
| <option name="flavor" value="{{.Code}}">{{.Value}}</option> | |||||
| {{end}} | |||||
| {{end}} | |||||
| </select> | |||||
| </div>--> | |||||
| <div class="required unite min_title inline field" id="flaver_name"> | <div class="required unite min_title inline field" id="flaver_name"> | ||||
| <label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.standard"}}</label> | <label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.standard"}}</label> | ||||
| <select id="__specs__" class="ui dropdown width80" style='width:385px' name="spec_id" ovalue="{{.spec_id}}" {{if .CloudBrainPaySwitch}}blance="{{.PointAccount.Balance}}"{{end}}></select> | <select id="__specs__" class="ui dropdown width80" style='width:385px' name="spec_id" ovalue="{{.spec_id}}" {{if .CloudBrainPaySwitch}}blance="{{.PointAccount.Balance}}"{{end}}></select> | ||||
| @@ -289,7 +261,7 @@ | |||||
| <button class="ui create_train_job green button"> | <button class="ui create_train_job green button"> | ||||
| {{.i18n.Tr "repo.cloudbrain.new"}} | {{.i18n.Tr "repo.cloudbrain.new"}} | ||||
| </button> | </button> | ||||
| <a class="ui button" href="/">{{.i18n.Tr "repo.cloudbrain.cancel"}}</a> | |||||
| <a class="ui button" href="{{.RepoLink}}/modelarts/train-job">{{.i18n.Tr "repo.cloudbrain.cancel"}}</a> | |||||
| </div> | </div> | ||||
| <!-- 模态框 --> | <!-- 模态框 --> | ||||
| @@ -300,239 +272,11 @@ | |||||
| </div> | </div> | ||||
| {{template "base/footer" .}} | {{template "base/footer" .}} | ||||
| <script src="{{StaticUrlPrefix}}/js/specsuse.js?v={{MD5 AppVer}}" type="text/javascript"></script> | <script src="{{StaticUrlPrefix}}/js/specsuse.js?v={{MD5 AppVer}}" type="text/javascript"></script> | ||||
| <script src="{{StaticUrlPrefix}}/js/cloudbrainNew.js?v={{MD5 AppVer}}" type="text/javascript"></script> | |||||
| <script> | <script> | ||||
| let url_href = location.pathname.split('/create_version')[0] | |||||
| let url_post = location.pathname | |||||
| let version_name = location.search.split('?version_name=')[1] | let version_name = location.search.split('?version_name=')[1] | ||||
| $("#parents_version").val(version_name) | $("#parents_version").val(version_name) | ||||
| $(".ui.button").attr('href',url_href) | |||||
| $(".ui.form").attr('action',url_post) | |||||
| $("input[name=version_name]").attr('value',version_name) | $("input[name=version_name]").attr('value',version_name) | ||||
| $('select.dropdown') | |||||
| .dropdown(); | |||||
| $('.menu .item') | |||||
| .tab(); | |||||
| let sever_num = $('#trainjob_work_server_num') | |||||
| $('.add').click(function(){ | |||||
| sever_num.val(parseInt(sever_num.val())+1) | |||||
| if(sever_num.val()>=26){ | |||||
| sever_num.val(parseInt(sever_num.val())-1) | |||||
| } | |||||
| }) | |||||
| $('.min').click(function(){ | |||||
| sever_num.val(parseInt(sever_num.val())-1) | |||||
| if(sever_num.val()<=0){ | |||||
| sever_num.val(parseInt(sever_num.val())+1) | |||||
| } | |||||
| }) | |||||
| // 参数增加、删除、修改、保存 | |||||
| function Add_parameter(i){ | |||||
| let placeholder_value='{{.i18n.Tr "repo.modelarts.train_job.parameter_value"}}' | |||||
| let placeholder_name='{{.i18n.Tr "repo.modelarts.train_job.parameter_name"}}' | |||||
| value = '<div class="two fields width85" id= "para'+ i +'">' + | |||||
| '<div class="field">' + | |||||
| '<input type="text" name="shipping_first-name" required placeholder="' + placeholder_name+ '">' + | |||||
| '</div> ' + | |||||
| '<div class="field"> ' + | |||||
| '<input type="text" name="shipping_last-name" required placeholder="' + placeholder_value+ '">' + | |||||
| '</div>'+ | |||||
| '<span>' + | |||||
| '<i class="trash icon">' + | |||||
| '</i>' + | |||||
| '</span>' + | |||||
| '</div>' | |||||
| $(".dynamic.field").append(value) | |||||
| } | |||||
| $('#add_run_para').click(function(){ | |||||
| var len = $(".dynamic.field .two.fields").length | |||||
| Add_parameter(len) | |||||
| }); | |||||
| $(".dynamic.field").on("click",".trash.icon", function() { | |||||
| var index = $(this).parent().parent().index() | |||||
| $(this).parent().parent().remove() | |||||
| var len = $(".dynamic.field .two.fields").length | |||||
| $(".dynamic.field .two.fields").each(function(){ | |||||
| var cur_index = $(this).index() | |||||
| $(this).attr('id', 'para' + cur_index) | |||||
| }) | |||||
| }); | |||||
| $('.ui.parameter.green.button').click(function(){ | |||||
| var parameters = []; | |||||
| $('table tr').each(function() { | |||||
| $(this).find('td:eq(1)').each(function(){ | |||||
| parameters.push($(this).text()); | |||||
| }) | |||||
| $(this).find('input').each(function(){ | |||||
| parameters.push($(this).text()) | |||||
| }) | |||||
| }); | |||||
| $('.ui.parameter.modal') | |||||
| .modal('hide'); | |||||
| for(var i = 2; i < parameters.length; i++){ | |||||
| switch(i) { | |||||
| // 数据集uuid待完成 | |||||
| // case (2): | |||||
| // console.log(1) | |||||
| // break; | |||||
| // $("#trainjob_datasets").val(parameters[i]); | |||||
| // console.log($("#trainjob_datasets").val()) | |||||
| case (3): | |||||
| $("input[name='boot_file']").val(parameters[i]); | |||||
| break; | |||||
| case (4): | |||||
| var para = parameters[i].split(" ") | |||||
| for(var j = 0; j < para.length; j++){ | |||||
| var para_name = para[j].split('=')[0] | |||||
| var para_value = para[j].split('=')[1] | |||||
| var len = $(".dynamic.field .two.fields").length | |||||
| Add_parameter(len) | |||||
| var pid = 'para' + len | |||||
| $(".dynamic.field"+ " #" + pid + "").find("input[name=shipping_first-name]").val(para_name) | |||||
| $(".dynamic.field"+ " #" + pid + "").find("input[name=shipping_last-name]").val(para_value) | |||||
| } | |||||
| break; | |||||
| // 数据集pool_id待完成 | |||||
| // case (5): | |||||
| // $("select[name='pool_id']").val(parameters[i]); | |||||
| // break; | |||||
| case (6): | |||||
| $("input[name='work_server_number']").val(parameters[i]); | |||||
| break; | |||||
| } | |||||
| } | |||||
| }) | |||||
| $('.ui.save.checkbox').click(function(){ | |||||
| $(this).checkbox({ | |||||
| onChange: function(){ | |||||
| if ($('.ui.save.checkbox').checkbox('is checked')){ | |||||
| $('#save_para').removeClass("disabled") | |||||
| }else{ | |||||
| $('#save_para').addClass("disabled") | |||||
| } | |||||
| } | |||||
| }); | |||||
| }) | |||||
| $('.question.circle.icon').hover(function(){ | |||||
| $(this).popup('show') | |||||
| }); | |||||
| $(".item.active.parameter_config").click(function(){ | |||||
| $('.ui.parameter.modal') | |||||
| .modal('setting', 'closable', false) | |||||
| .modal('show'); | |||||
| }) | |||||
| $('.ui.deny.button').click(function(){ | |||||
| $('.ui.parameter.modal') | |||||
| .modal('hide'); | |||||
| }) | |||||
| $('select.dropdown') | |||||
| .dropdown(); | |||||
| var isValidate = false; | |||||
| function validate(){ | |||||
| $('.ui.form') | |||||
| .form({ | |||||
| on: 'blur', | |||||
| inline:true, | |||||
| fields: { | |||||
| boot_file: { | |||||
| identifier : 'boot_file', | |||||
| rules: [ | |||||
| { | |||||
| type: 'regExp[/.+\.py$/g]', | |||||
| prompt : '启动文件必须为.py结尾' | |||||
| } | |||||
| ] | |||||
| }, | |||||
| job_name:{ | |||||
| identifier : 'job_name', | |||||
| rules: [ | |||||
| { | |||||
| type: 'regExp[/^[a-zA-Z0-9-_]{1,36}$/]', | |||||
| prompt : '只包含大小写字母、数字、_和-,最长36个字符。' | |||||
| } | |||||
| ] | |||||
| }, | |||||
| display_job_name:{ | |||||
| identifier : 'display_job_name', | |||||
| rules: [ | |||||
| { | |||||
| type: 'regExp[/^[a-zA-Z0-9-_]{1,36}$/]', | |||||
| prompt : '只包含大小写字母、数字、_和-,最长36个字符。' | |||||
| } | |||||
| ] | |||||
| }, | |||||
| attachment:{ | |||||
| identifier : 'attachment', | |||||
| rules: [ | |||||
| { | |||||
| type: 'empty', | |||||
| prompt : '选择一个数据集' | |||||
| } | |||||
| ] | |||||
| }, | |||||
| spec_id: { | |||||
| identifier: 'spec_id', | |||||
| rules: [{ type: 'empty' }] | |||||
| } | |||||
| }, | |||||
| onSuccess: function(){ | |||||
| // $('.ui.page.dimmer').dimmer('show') | |||||
| document.getElementById("mask").style.display = "block" | |||||
| isValidate = true; | |||||
| }, | |||||
| onFailure: function(e){ | |||||
| isValidate = false; | |||||
| return false; | |||||
| } | |||||
| }) | |||||
| } | |||||
| document.onreadystatechange = function() { | |||||
| if (document.readyState === "complete") { | |||||
| document.getElementById("mask").style.display = "none" | |||||
| } | |||||
| } | |||||
| function send_run_para(){ | |||||
| var run_parameters = [] | |||||
| var msg = {} | |||||
| $(".dynamic.field .two.fields").each(function(){ | |||||
| var para_name = $(this).find('input[name=shipping_first-name]').val() | |||||
| var para_value = $(this).find('input[name=shipping_last-name]').val() | |||||
| run_parameters.push({"label": para_name, "value": para_value}) | |||||
| }) | |||||
| msg["parameter"] = run_parameters | |||||
| msg = JSON.stringify(msg) | |||||
| $('#store_run_para').val(msg) | |||||
| } | |||||
| function get_name(){ | |||||
| let name1=$("#engine_name .text").text() | |||||
| let name2=$("#flaver_name .text").text() | |||||
| $("input#ai_engine_name").val(name1) | |||||
| $("input#ai_flaver_name").val(name2) | |||||
| } | |||||
| validate() | |||||
| $('.ui.create_train_job.green.button').click(function(e) { | |||||
| get_name() | |||||
| send_run_para() | |||||
| validate() | |||||
| }) | |||||
| ;(function() { | ;(function() { | ||||
| var SPECS = {{ .Specs }}; | var SPECS = {{ .Specs }}; | ||||
| var showPoint = {{ .CloudBrainPaySwitch }}; | var showPoint = {{ .CloudBrainPaySwitch }}; | ||||
| @@ -16,10 +16,10 @@ | |||||
| text-align: center; | text-align: center; | ||||
| } | } | ||||
| </style> | </style> | ||||
| <div class="ui container"> | |||||
| <div class="ui container rule-container" style="display:none;"> | |||||
| <h1 class="ui center am-pt-30 am-pb-20">个人算力积分奖励规则</h1> | <h1 class="ui center am-pt-30 am-pb-20">个人算力积分奖励规则</h1> | ||||
| <div class="ui divider am-pb-10"></div> | <div class="ui divider am-pb-10"></div> | ||||
| <p>说明:单日用户积分的获取上限为50分。</p> | |||||
| <p>说明:单日用户积分的获取上限为<span class="daily-limit"> - </span>分。该积分仅用于算力资源使用,打榜活动积分将另行计算。</p> | |||||
| <table class="m-table"> | <table class="m-table"> | ||||
| <tr> | <tr> | ||||
| <th style="width:200px;">奖励名称</th> | <th style="width:200px;">奖励名称</th> | ||||
| @@ -27,85 +27,126 @@ | |||||
| <th style="width:200px;">上限值</th> | <th style="width:200px;">上限值</th> | ||||
| <th>奖励细节澄清</th> | <th>奖励细节澄清</th> | ||||
| </tr> | </tr> | ||||
| <tr> | |||||
| <tr key="34"> | |||||
| <td class="t-center">完成微信扫码验证</td> | <td class="t-center">完成微信扫码验证</td> | ||||
| <td class="t-center">50</td> | |||||
| <td class="t-center">累计积分获取上限50</td> | |||||
| <td>1、首次完成微信扫码验证,即获取50积分。<br>2、同个账号,更换微信号码再验证不重复给积分。<br>3、同一个微信,绑定第一个账号时奖励50分,下次绑定其他账号时不再奖励。</td> | |||||
| <td class="t-center point">-</td> | |||||
| <td class="t-center"><span class="typ">累计</span>积分获取上限<span class="limit"> - </span></td> | |||||
| <td>1、首次完成微信扫码验证,即获取积分。<br>2、同个账号,更换微信号码再验证不重复给积分。<br>3、同一个微信,绑定第一个账号时奖励积分,下次绑定其他账号时不再奖励。</td> | |||||
| </tr> | </tr> | ||||
| <tr> | |||||
| <tr key="1"> | |||||
| <td class="t-center">创建或Fork公开项目</td> | <td class="t-center">创建或Fork公开项目</td> | ||||
| <td class="t-center">1</td> | |||||
| <td class="t-center">每日积分获取上限3</td> | |||||
| <td class="t-center point">-</td> | |||||
| <td class="t-center"><span class="typ">每日</span>积分获取上限<span class="limit"> - </span></td> | |||||
| <td>请注意项目质量,请勿复制粘贴或者重复公开项目,任何非常规的以公开项目去获取积分的行为将被认定为积分舞弊,将扣除所有积分。</td> | <td>请注意项目质量,请勿复制粘贴或者重复公开项目,任何非常规的以公开项目去获取积分的行为将被认定为积分舞弊,将扣除所有积分。</td> | ||||
| </tr> | </tr> | ||||
| <tr> | |||||
| <tr key="7"> | |||||
| <td class="t-center">每日提出PR</td> | <td class="t-center">每日提出PR</td> | ||||
| <td class="t-center">1</td> | |||||
| <td class="t-center">每日积分获取上限3</td> | |||||
| <td class="t-center point">-</td> | |||||
| <td class="t-center"><span class="typ">每日</span>积分获取上限<span class="limit"> - </span></td> | |||||
| <td></td> | <td></td> | ||||
| </tr> | </tr> | ||||
| <tr> | |||||
| <tr key="40"> | |||||
| <td class="t-center">每日commit</td> | <td class="t-center">每日commit</td> | ||||
| <td class="t-center">1</td> | |||||
| <td class="t-center">每日积分获取上限3</td> | |||||
| <td class="t-center point">-</td> | |||||
| <td class="t-center"><span class="typ">每日</span>积分获取上限<span class="limit"> - </span></td> | |||||
| <td>通过前台界面和后台命令行方式commit,都可获得奖励积分。</td> | <td>通过前台界面和后台命令行方式commit,都可获得奖励积分。</td> | ||||
| </tr> | </tr> | ||||
| <tr> | |||||
| <tr key="6"> | |||||
| <td class="t-center">每日提出任务</td> | <td class="t-center">每日提出任务</td> | ||||
| <td class="t-center">1</td> | |||||
| <td class="t-center">每日积分获取上限3</td> | |||||
| <td class="t-center point">-</td> | |||||
| <td class="t-center"><span class="typ">每日</span>积分获取上限<span class="limit"> - </span></td> | |||||
| <td></td> | <td></td> | ||||
| </tr> | </tr> | ||||
| <tr> | |||||
| <tr key="10"> | |||||
| <td class="t-center">发表评论</td> | <td class="t-center">发表评论</td> | ||||
| <td class="t-center">1</td> | |||||
| <td class="t-center">每日积分获取上限2</td> | |||||
| <td class="t-center point">-</td> | |||||
| <td class="t-center"><span class="typ">每日</span>积分获取上限<span class="limit"> - </span></td> | |||||
| <td>禁止空评论或评论后马上删除等非正常获取积分的方式,一经发现将扣除所有积分。</td> | <td>禁止空评论或评论后马上删除等非正常获取积分的方式,一经发现将扣除所有积分。</td> | ||||
| </tr> | </tr> | ||||
| <tr> | |||||
| <tr key="24"> | |||||
| <td class="t-center">上传数据集文件</td> | <td class="t-center">上传数据集文件</td> | ||||
| <td class="t-center">1</td> | |||||
| <td class="t-center">每日积分获取上限1</td> | |||||
| <td class="t-center point">-</td> | |||||
| <td class="t-center"><span class="typ">每日</span>积分获取上限<span class="limit"> - </span></td> | |||||
| <td>请注意数据集质量,请勿复制粘贴或者重复公开数据集,任何非常规的以公开数据集去获取积分的行为将被认定为积分舞弊,将扣除所有积分。</td> | <td>请注意数据集质量,请勿复制粘贴或者重复公开数据集,任何非常规的以公开数据集去获取积分的行为将被认定为积分舞弊,将扣除所有积分。</td> | ||||
| </tr> | </tr> | ||||
| <tr> | |||||
| <tr key="36"> | |||||
| <td class="t-center">数据集被平台推荐</td> | <td class="t-center">数据集被平台推荐</td> | ||||
| <td class="t-center">5</td> | |||||
| <td class="t-center">每日积分获取上限15</td> | |||||
| <td class="t-center point">-</td> | |||||
| <td class="t-center"><span class="typ">每日</span>积分获取上限<span class="limit"> - </span></td> | |||||
| <td>仅统计属于个人的数据集,属于组织的数据集暂不统计。</td> | <td>仅统计属于个人的数据集,属于组织的数据集暂不统计。</td> | ||||
| </tr> | </tr> | ||||
| <tr> | |||||
| <tr key="30"> | |||||
| <td class="t-center">导入新模型</td> | <td class="t-center">导入新模型</td> | ||||
| <td class="t-center">1</td> | |||||
| <td class="t-center">每日积分获取上限3</td> | |||||
| <td class="t-center point">-</td> | |||||
| <td class="t-center"><span class="typ">每日</span>积分获取上限<span class="limit"> - </span></td> | |||||
| <td>请注意模型质量,请勿重复导入相同模型,任何非常规的以导入新模型去获取 积分的行为将被认定为积分舞弊,将扣除所有积分。</td> | <td>请注意模型质量,请勿重复导入相同模型,任何非常规的以导入新模型去获取 积分的行为将被认定为积分舞弊,将扣除所有积分。</td> | ||||
| </tr> | </tr> | ||||
| <tr> | |||||
| <tr key="35"> | |||||
| <td class="t-center">每日运行云脑任务</td> | <td class="t-center">每日运行云脑任务</td> | ||||
| <td class="t-center">10</td> | |||||
| <td class="t-center">每日积分获取上限10</td> | |||||
| <td class="t-center point">-</td> | |||||
| <td class="t-center"><span class="typ">每日</span>积分获取上限<span class="limit"> - </span></td> | |||||
| <td> 每日运行调试、训练、推理、评测中任何一种任务,即可获得。</td> | <td> 每日运行调试、训练、推理、评测中任何一种任务,即可获得。</td> | ||||
| </tr> | </tr> | ||||
| <tr> | |||||
| <tr key="37"> | |||||
| <td class="t-center">提交新公开镜像</td> | <td class="t-center">提交新公开镜像</td> | ||||
| <td class="t-center">1</td> | |||||
| <td class="t-center">每日积分获取上限3</td> | |||||
| <td class="t-center point">-</td> | |||||
| <td class="t-center"><span class="typ">每日</span>积分获取上限<span class="limit"> - </span></td> | |||||
| <td></td> | <td></td> | ||||
| </tr> | </tr> | ||||
| <tr> | |||||
| <tr key="38"> | |||||
| <td class="t-center">镜像被平台推荐</td> | <td class="t-center">镜像被平台推荐</td> | ||||
| <td class="t-center">5</td> | |||||
| <td class="t-center">每日积分获取上限15</td> | |||||
| <td class="t-center point">-</td> | |||||
| <td class="t-center"><span class="typ">每日</span>积分获取上限<span class="limit"> - </span></td> | |||||
| <td></td> | <td></td> | ||||
| </tr> | </tr> | ||||
| <tr> | |||||
| <tr key="39"> | |||||
| <td class="t-center">首次更换头像</td> | <td class="t-center">首次更换头像</td> | ||||
| <td class="t-center">2</td> | |||||
| <td class="t-center">累计积分获取上限2</td> | |||||
| <td>首次更换头像,积分+2。</td> | |||||
| <td class="t-center point">-</td> | |||||
| <td class="t-center"><span class="typ">累计</span>积分获取上限<span class="limit"> - </span></td> | |||||
| <td>首次更换头像,获得积分。</td> | |||||
| </tr> | </tr> | ||||
| </table> | </table> | ||||
| </div> | </div> | ||||
| {{template "base/footer" .}} | |||||
| {{template "base/footer" .}} | |||||
| <script> | |||||
| ;(function() { | |||||
| var ruleContainer = $('.rule-container'); | |||||
| var dailyLimitEl = ruleContainer.find('.daily-limit'); | |||||
| var ruleTrs = ruleContainer.find('tr[key]'); | |||||
| $.ajax({ | |||||
| url: '/reward/point/rule/config', | |||||
| type: "get", | |||||
| data: {}, | |||||
| contentType: "application/json; charset=utf-8", | |||||
| success(res) { | |||||
| if (res && res.Code === 0) { | |||||
| var data = res.Data; | |||||
| dailyLimitEl.text(data.UserDailyLimit); | |||||
| var taskRules = data.TaskRules; | |||||
| for (var i = 0, iLen = ruleTrs.length; i < iLen; i++) { | |||||
| var ruleTr = ruleTrs.eq(i); | |||||
| var key = ruleTr.attr('key'); | |||||
| var findOr = false; | |||||
| for (var j = 0, jLen = taskRules.length; j < jLen; j++) { | |||||
| var taskRule = taskRules[j]; | |||||
| if (taskRule.TaskCode == key) { | |||||
| ruleTr.find('.point').text(taskRule.AwardAmount); | |||||
| ruleTr.find('.typ').text(taskRule.RefreshRate == 'DAILY' ? '每日' : taskRule.RefreshRate == 'NOT_CYCLE' ? '累计' : taskRule.RefreshRate); | |||||
| ruleTr.find('.limit').text(taskRule.LimitNum); | |||||
| findOr = true; | |||||
| break; | |||||
| } | |||||
| } | |||||
| if (!findOr) ruleTr.hide(); | |||||
| } | |||||
| } | |||||
| ruleContainer.show(); | |||||
| }, | |||||
| error(err) { | |||||
| console.log(err); | |||||
| ruleContainer.show(); | |||||
| }, | |||||
| }); | |||||
| })(); | |||||
| </script> | |||||
| @@ -229,6 +229,14 @@ | |||||
| </a> | </a> | ||||
| </div> | </div> | ||||
| {{end}} | |||||
| <!-- 修改任务 --> | |||||
| {{if eq .JobType "TRAIN"}} | |||||
| <div class="ui compact buttons"> | |||||
| <a style="padding: 0.5rem 1rem;" class="ui basic blue button" href="{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}{{if eq .Cloudbrain.Type 1}}/modelarts/train-job/{{.JobID}}{{else if eq .Cloudbrain.Type 0}}/cloudbrain/train-job/{{.JobID}}{{else if eq .Cloudbrain.Type 2}}/grampus/train-job/{{.JobID}}{{end}}/create_version{{if .VersionName}}?version_name={{.VersionName}}{{end}}"> | |||||
| {{$.i18n.Tr "repo.modelarts.modify"}} | |||||
| </a> | |||||
| </div> | |||||
| {{end}} | {{end}} | ||||
| <!-- 删除任务 --> | <!-- 删除任务 --> | ||||
| <form class="ui compact buttons" id="delForm-{{$JobID}}" | <form class="ui compact buttons" id="delForm-{{$JobID}}" | ||||
| @@ -21,6 +21,11 @@ | |||||
| v-if="confirmDatasetList && confirmFlag" | v-if="confirmDatasetList && confirmFlag" | ||||
| > | > | ||||
| <input type="hidden" name="attachment" :value="confirmDatasetList" /> | <input type="hidden" name="attachment" :value="confirmDatasetList" /> | ||||
| <input | |||||
| type="hidden" | |||||
| name="dataset_name" | |||||
| :value="confirmDatasetNameList" | |||||
| /> | |||||
| <div class="multi-dataset-box"> | <div class="multi-dataset-box"> | ||||
| <span | <span | ||||
| v-for="(item, index) in confirmChecklist" | v-for="(item, index) in confirmChecklist" | ||||
| @@ -600,6 +605,7 @@ export default { | |||||
| checkList: [], | checkList: [], | ||||
| confirmChecklist: [], | confirmChecklist: [], | ||||
| confirmDatasetList: "", | confirmDatasetList: "", | ||||
| confirmDatasetNameList: "", | |||||
| confirmFlag: false, | confirmFlag: false, | ||||
| saveStatusList: [], | saveStatusList: [], | ||||
| @@ -928,6 +934,7 @@ export default { | |||||
| }, | }, | ||||
| confirmDataset() { | confirmDataset() { | ||||
| this.confirmDatasetList = this.saveStatusList.join(";"); | this.confirmDatasetList = this.saveStatusList.join(";"); | ||||
| this.confirmDatasetNameList = this.checkList.join(";"); | |||||
| this.confirmChecklist = this.checkList; | this.confirmChecklist = this.checkList; | ||||
| this.dialogVisible = false; | this.dialogVisible = false; | ||||
| this.confirmFlag = true; | this.confirmFlag = true; | ||||
| @@ -7,9 +7,9 @@ | |||||
| v-if="benchmarkNew" | v-if="benchmarkNew" | ||||
| class="label-fix-width" | class="label-fix-width" | ||||
| style="font-weight: normal" | style="font-weight: normal" | ||||
| >{{i18n.image_label}}</label | |||||
| >{{ i18n.image_label }}</label | |||||
| > | > | ||||
| <label v-else>{{i18n.image_label}}</label> | |||||
| <label v-else>{{ i18n.image_label }}</label> | |||||
| <input | <input | ||||
| v-if="benchmarkNew" | v-if="benchmarkNew" | ||||
| type="text" | type="text" | ||||
| @@ -17,6 +17,7 @@ | |||||
| :value="imageAddress" | :value="imageAddress" | ||||
| style="width: 48.5%" | style="width: 48.5%" | ||||
| :placeholder="i18n.image_select_placeholder" | :placeholder="i18n.image_select_placeholder" | ||||
| required | |||||
| /> | /> | ||||
| <input | <input | ||||
| v-else | v-else | ||||
| @@ -24,15 +25,20 @@ | |||||
| name="image" | name="image" | ||||
| :value="imageAddress" | :value="imageAddress" | ||||
| :placeholder="i18n.image_select_placeholder" | :placeholder="i18n.image_select_placeholder" | ||||
| required | |||||
| /> | /> | ||||
| <el-button | <el-button | ||||
| type="text" | type="text" | ||||
| @click="dialogVisible = true" | @click="dialogVisible = true" | ||||
| icon="el-icon-plus" | icon="el-icon-plus" | ||||
| style="color: #0366d6" | style="color: #0366d6" | ||||
| >{{i18n.image_select}} | |||||
| >{{ i18n.image_select }} | |||||
| </el-button> | </el-button> | ||||
| <el-dialog :title="i18n.image_select" :visible.sync="dialogVisible" width="50%"> | |||||
| <el-dialog | |||||
| :title="i18n.image_select" | |||||
| :visible.sync="dialogVisible" | |||||
| width="50%" | |||||
| > | |||||
| <div | <div | ||||
| class="ui icon input" | class="ui icon input" | ||||
| style="z-index: 9999; position: absolute; right: 50px; height: 30px" | style="z-index: 9999; position: absolute; right: 50px; height: 30px" | ||||
| @@ -48,7 +54,11 @@ | |||||
| /> | /> | ||||
| </div> | </div> | ||||
| <el-tabs v-model="activeName" @tab-click="handleClick"> | <el-tabs v-model="activeName" @tab-click="handleClick"> | ||||
| <el-tab-pane :label="i18n.image_public" name="first" v-loading="loadingPublic"> | |||||
| <el-tab-pane | |||||
| :label="i18n.image_public" | |||||
| name="first" | |||||
| v-loading="loadingPublic" | |||||
| > | |||||
| <div | <div | ||||
| style=" | style=" | ||||
| display: flex; | display: flex; | ||||
| @@ -120,7 +130,7 @@ | |||||
| selectImages(publicData.place, publicData.tag) | selectImages(publicData.place, publicData.tag) | ||||
| " | " | ||||
| > | > | ||||
| {{i18n.image_use}} | |||||
| {{ i18n.image_use }} | |||||
| </button> | </button> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| @@ -446,4 +446,142 @@ export default async function initCloudrainSow() { | |||||
| html += "</div>"; | html += "</div>"; | ||||
| $(`#dir_list${version_name}`).append(html); | $(`#dir_list${version_name}`).append(html); | ||||
| } | } | ||||
| let nameMap, nameList; | |||||
| let RepoLink = $(".cloudbrain-type").data("repo-link"); | |||||
| let type = $(".cloudbrain-type").data("cloudbrain-type"); | |||||
| let flagModel = $(".cloudbrain-type").data("flag-model"); | |||||
| // 获取模型列表和模型名称对应的模型版本 | |||||
| $(document).ready(function () { | |||||
| if (!flagModel) return; | |||||
| else { | |||||
| $.get( | |||||
| `${RepoLink}/modelmanage/query_model_for_predict?type=${type}`, | |||||
| (data) => { | |||||
| nameMap = data.nameMap; | |||||
| nameList = data.nameList; | |||||
| let html = `<div class="item"></div>`; | |||||
| nameList.forEach((element) => { | |||||
| html += `<div class="item" data-value=${element}>${element}</div>`; | |||||
| }); | |||||
| if (nameList.length !== 0) { | |||||
| $("#model_name").append(html); | |||||
| } | |||||
| let faildModelName = $('input[name="model_name"]').val(); | |||||
| let faildModelVersion = $('input[name="model_version"]').val(); | |||||
| let faildTrainUrl = $('input[name="pre_train_model_url"]').val(); | |||||
| let faildCkptName = $('input[name="ckpt_name"]').val(); | |||||
| // 新建错误的表单返回初始化 | |||||
| if (faildModelName && nameList.includes(faildModelName)) { | |||||
| $("#select_model").dropdown("set text", faildModelName); | |||||
| $("#select_model").dropdown("set value", faildModelName); | |||||
| $("#select_model_version").dropdown("set text", faildModelVersion); | |||||
| $("#select_model_version").dropdown("set value", faildTrainUrl); | |||||
| $("#select_model_checkpoint").dropdown("set text", faildCkptName); | |||||
| $("#select_model_checkpoint").dropdown("set value", faildCkptName); | |||||
| } | |||||
| } | |||||
| ); | |||||
| } | |||||
| $("#select_model").dropdown({ | |||||
| onChange: function (value, text, $selectedItem) { | |||||
| $("#model_name_version").empty(); | |||||
| if (value) { | |||||
| let html = ""; | |||||
| nameMap[value].forEach((element) => { | |||||
| let { TrainTaskInfo } = element; | |||||
| TrainTaskInfo = JSON.parse(TrainTaskInfo); | |||||
| html += `<div class="item" data-label="${element.Label}" data-id="${element.ID}" data-value="${element.Path}">${element.Version}</div>`; | |||||
| }); | |||||
| $("#model_name_version").append(html); | |||||
| const initVersionText = $( | |||||
| "#model_name_version div.item:first-child" | |||||
| ).text(); | |||||
| const initVersionValue = $( | |||||
| "#model_name_version div.item:first-child" | |||||
| ).data("value"); | |||||
| $("#select_model_version").dropdown("set text", initVersionText); | |||||
| $("#select_model_version").dropdown( | |||||
| "set value", | |||||
| initVersionValue, | |||||
| initVersionText, | |||||
| $("#model_name_version div.item:first-child") | |||||
| ); | |||||
| } else { | |||||
| $("#select_model_version").dropdown("set text", ""); | |||||
| $("#select_model_version").dropdown("set value", ""); | |||||
| $("#select_model_checkpoint").dropdown("set text", ""); | |||||
| $("#select_model_checkpoint").dropdown("set value", ""); | |||||
| } | |||||
| }, | |||||
| }); | |||||
| $("#select_model_version").dropdown({ | |||||
| onChange: function (value, text, $selectedItem) { | |||||
| if (!value) return; | |||||
| const dataID = | |||||
| $selectedItem && $selectedItem[0].getAttribute("data-id"); | |||||
| $("input#ai_model_version").val(text); | |||||
| $("#select_model_checkpoint").addClass("loading"); | |||||
| $("#model_checkpoint").empty(); | |||||
| let html = ""; | |||||
| loadCheckpointList(dataID).then((res) => { | |||||
| res.forEach((element) => { | |||||
| const ckptSuffix = element.FileName.split("."); | |||||
| 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>`; | |||||
| } | |||||
| }); | |||||
| $("#model_checkpoint").append(html); | |||||
| $("#select_model_checkpoint").removeClass("loading"); | |||||
| const initVersionText = $( | |||||
| "#model_checkpoint div.item:first-child" | |||||
| ).text(); | |||||
| const initVersionValue = $( | |||||
| "#model_checkpoint div.item:first-child" | |||||
| ).data("value"); | |||||
| $("#select_model_checkpoint").dropdown("set text", initVersionText); | |||||
| $("#select_model_checkpoint").dropdown( | |||||
| "set value", | |||||
| initVersionValue, | |||||
| initVersionText, | |||||
| $("#model_name_version div.item:first-child") | |||||
| ); | |||||
| }); | |||||
| }, | |||||
| }); | |||||
| }); | |||||
| function loadCheckpointList(value) { | |||||
| return new Promise((resolve, reject) => { | |||||
| $.get( | |||||
| `${RepoLink}/modelmanage/query_modelfile_for_predict`, | |||||
| { ID: value }, | |||||
| (data) => { | |||||
| resolve(data); | |||||
| } | |||||
| ); | |||||
| }); | |||||
| } | |||||
| } | } | ||||
| @@ -0,0 +1,161 @@ | |||||
| let form = document.getElementById("form_id"); | |||||
| let createFlag = false; | |||||
| let flag; | |||||
| form.onsubmit = function (e) { | |||||
| if (createFlag) return false; | |||||
| createFlag = true; | |||||
| }; | |||||
| $("select.dropdown").dropdown(); | |||||
| $(document).keydown(function (event) { | |||||
| switch (event.keyCode) { | |||||
| case 13: | |||||
| return false; | |||||
| } | |||||
| }); | |||||
| $(".menu .item").tab(); | |||||
| $(document).ready(createParamter()); | |||||
| function createParamter() { | |||||
| let params = $(".dynamic.field").data("params"); | |||||
| params && | |||||
| params.parameter.forEach((item, index) => { | |||||
| Add_parameter(index, (flag = true), item); | |||||
| }); | |||||
| } | |||||
| // 参数增加、删除、修改、保存 | |||||
| function Add_parameter(i, flag = false, paramsObject = {}) { | |||||
| let value = ""; | |||||
| value += `<div class="two fields width85" id= "para${i}">`; | |||||
| value += '<div class="field">'; | |||||
| let placeholder_value = $(".dynamic.field").data("params-value"); | |||||
| let placeholder_name = $(".dynamic.field").data("params-name"); | |||||
| if (flag) { | |||||
| value += `<input type="text" class="shipping_first-name" value="${paramsObject.label}">`; | |||||
| } else { | |||||
| value += | |||||
| '<input type="text" class="shipping_first-name" required placeholder="' + | |||||
| placeholder_name + | |||||
| '">'; | |||||
| } | |||||
| value += "</div>"; | |||||
| value += '<div class="field">'; | |||||
| if (flag) { | |||||
| value += `<input type="text" class="shipping_last-name" value="${paramsObject.value}">`; | |||||
| } else { | |||||
| value += | |||||
| '<input type="text" class="shipping_last-name" required placeholder="' + | |||||
| placeholder_value + | |||||
| '">'; | |||||
| } | |||||
| value += "</div>"; | |||||
| value += '<span><i class="trash icon"></i></span>'; | |||||
| value += "</div>"; | |||||
| $(".dynamic.field").append(value); | |||||
| } | |||||
| $("#add_run_para").click(function () { | |||||
| var len = $(".dynamic.field .two.fields").length; | |||||
| Add_parameter(len); | |||||
| }); | |||||
| $(".dynamic.field").on("click", ".trash.icon", function () { | |||||
| var index = $(this).parent().parent().index(); | |||||
| $(this).parent().parent().remove(); | |||||
| var len = $(".dynamic.field .two.fields").length; | |||||
| $(".dynamic.field .two.fields").each(function () { | |||||
| var cur_index = $(this).index(); | |||||
| $(this).attr("id", "para" + cur_index); | |||||
| }); | |||||
| }); | |||||
| $(".question.circle.icon").hover(function () { | |||||
| $(this).popup("show"); | |||||
| }); | |||||
| var isValidate = false; | |||||
| function validate() { | |||||
| $(".ui.form").form({ | |||||
| on: "blur", | |||||
| inline: true, | |||||
| fields: { | |||||
| boot_file: { | |||||
| identifier: "boot_file", | |||||
| rules: [ | |||||
| { | |||||
| type: "regExp[/.+.py$/g]", | |||||
| prompt: "启动文件必须为.py结尾", | |||||
| }, | |||||
| ], | |||||
| }, | |||||
| job_name: { | |||||
| identifier: "job_name", | |||||
| rules: [ | |||||
| { | |||||
| type: "regExp[/^[a-zA-Z0-9-_]{1,36}$/]", | |||||
| prompt: "只包含大小写字母、数字、_和-,最长36个字符。", | |||||
| }, | |||||
| ], | |||||
| }, | |||||
| display_job_name: { | |||||
| identifier: "display_job_name", | |||||
| rules: [ | |||||
| { | |||||
| type: "regExp[/^[a-zA-Z0-9-_]{1,36}$/]", | |||||
| prompt: "只包含大小写字母、数字、_和-,最长36个字符。", | |||||
| }, | |||||
| ], | |||||
| }, | |||||
| attachment: { | |||||
| identifier: "attachment", | |||||
| rules: [ | |||||
| { | |||||
| type: "empty", | |||||
| prompt: "选择一个数据集", | |||||
| }, | |||||
| ], | |||||
| }, | |||||
| spec_id: { | |||||
| identifier: "spec_id", | |||||
| rules: [{ type: "empty" }], | |||||
| }, | |||||
| }, | |||||
| onSuccess: function () { | |||||
| // $('.ui.page.dimmer').dimmer('show') | |||||
| document.getElementById("mask").style.display = "block"; | |||||
| isValidate = true; | |||||
| }, | |||||
| onFailure: function (e) { | |||||
| isValidate = false; | |||||
| return false; | |||||
| }, | |||||
| }); | |||||
| } | |||||
| document.onreadystatechange = function () { | |||||
| if (document.readyState === "complete") { | |||||
| document.getElementById("mask").style.display = "none"; | |||||
| } | |||||
| }; | |||||
| function send_run_para() { | |||||
| var run_parameters = []; | |||||
| var msg = {}; | |||||
| $(".dynamic.field .two.fields").each(function () { | |||||
| var para_name = $(this).find("input.shipping_first-name").val(); | |||||
| var para_value = $(this).find("input.shipping_last-name").val(); | |||||
| run_parameters.push({ label: para_name, value: para_value }); | |||||
| }); | |||||
| msg["parameter"] = run_parameters; | |||||
| msg = JSON.stringify(msg); | |||||
| $("#store_run_para").val(msg); | |||||
| } | |||||
| function get_name() { | |||||
| let name1 = $("#engine_name .text").text(); | |||||
| let name2 = $("#flaver_name .text").text(); | |||||
| $("input#ai_engine_name").val(name1); | |||||
| $("input#ai_flaver_name").val(name2); | |||||
| } | |||||
| validate(); | |||||
| $(".ui.create_train_job.green.button").click(function (e) { | |||||
| get_name(); | |||||
| send_run_para(); | |||||
| validate(); | |||||
| }); | |||||
| @@ -16,11 +16,11 @@ | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div class="__r_p_summary"> | <div class="__r_p_summary"> | ||||
| <div class="__r_p_summary_item-c __flex-1"> | |||||
| <div class="__r_p_summary_item-c __flex-1" style="position:relative;"> | |||||
| <div class="__val">{{ summaryInfo.available }}</div> | <div class="__val">{{ summaryInfo.available }}</div> | ||||
| <div class="__exp">{{ $t('CurrAvailableCalcPoints') }}</div> | <div class="__exp">{{ $t('CurrAvailableCalcPoints') }}</div> | ||||
| </div> | |||||
| <div class="__r_p_summary_line"></div> | |||||
| <div class="__r_p_summary_line"></div> | |||||
| </div> | |||||
| <div class="__r_p_summary_item-c __flex-1"> | <div class="__r_p_summary_item-c __flex-1"> | ||||
| <div class="__val">{{ summaryInfo.gain }}</div> | <div class="__val">{{ summaryInfo.gain }}</div> | ||||
| <div class="__exp">{{ $t('totalGainCalcPoints') }}</div> | <div class="__exp">{{ $t('totalGainCalcPoints') }}</div> | ||||
| @@ -28,7 +28,7 @@ | |||||
| <div class="__r_p_summary_item-c __flex-1"> | <div class="__r_p_summary_item-c __flex-1"> | ||||
| <div class="__val">{{ summaryInfo.used }}</div> | <div class="__val">{{ summaryInfo.used }}</div> | ||||
| <div class="__exp">{{ $t('totalConsumeCalcPoints') }}</div> | <div class="__exp">{{ $t('totalConsumeCalcPoints') }}</div> | ||||
| </div> | |||||
| </div> | |||||
| </div> | </div> | ||||
| <div class="__r_p_tab"> | <div class="__r_p_tab"> | ||||
| <div class="__r_p_tab-item" :class="tabIndex === 0 ? '__focus' : ''" style="border-radius: 5px 0px 0px 5px" | <div class="__r_p_tab-item" :class="tabIndex === 0 ? '__focus' : ''" style="border-radius: 5px 0px 0px 5px" | ||||
| @@ -267,9 +267,12 @@ export default { | |||||
| } | } | ||||
| .__r_p_summary_line { | .__r_p_summary_line { | ||||
| position: absolute; | |||||
| top: 0; | |||||
| right: 1px; | |||||
| width: 1px; | width: 1px; | ||||
| height: 80%; | |||||
| background-color: rgb(212, 212, 213); | |||||
| height: 100%; | |||||
| border-right: 1px solid rgb(212, 212, 213); | |||||
| } | } | ||||
| .__r_p_tab { | .__r_p_tab { | ||||