| @@ -52,26 +52,46 @@ type Cloudbrain struct { | |||||
| ID int64 `xorm:"pk autoincr"` | ID int64 `xorm:"pk autoincr"` | ||||
| JobID string `xorm:"INDEX NOT NULL"` | JobID string `xorm:"INDEX NOT NULL"` | ||||
| JobType string `xorm:"INDEX NOT NULL DEFAULT 'DEBUG'"` | JobType string `xorm:"INDEX NOT NULL DEFAULT 'DEBUG'"` | ||||
| JobName string `xorm:"INDEX"` | |||||
| Status string `xorm:"INDEX"` | |||||
| UserID int64 `xorm:"INDEX"` | |||||
| RepoID int64 `xorm:"INDEX"` | |||||
| SubTaskName string `xorm:"INDEX"` | |||||
| JobName string | |||||
| Status string | |||||
| UserID int64 | |||||
| RepoID int64 | |||||
| SubTaskName string | |||||
| ContainerID string | ContainerID string | ||||
| ContainerIp string | ContainerIp string | ||||
| CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` | CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` | ||||
| UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` | UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` | ||||
| Duration int64 `xorm:"INDEX duration"` | |||||
| Duration int64 | |||||
| TrainJobDuration string | TrainJobDuration string | ||||
| DeletedAt time.Time `xorm:"deleted"` | DeletedAt time.Time `xorm:"deleted"` | ||||
| CanDebug bool `xorm:"-"` | CanDebug bool `xorm:"-"` | ||||
| CanDel bool `xorm:"-"` | CanDel bool `xorm:"-"` | ||||
| Type int `xorm:"INDEX DEFAULT 0"` | |||||
| VersionID int64 `xorm:"INDEX DEFAULT 0"` | |||||
| VersionName string | |||||
| Uuid string | |||||
| DatasetName string | |||||
| Type int | |||||
| VersionID int64 //版本id | |||||
| VersionName string `xorm:"INDEX"` //当前版本 | |||||
| Uuid string //数据集id | |||||
| DatasetName string | |||||
| VersionCount int //任务的当前版本数量,不包括删除的 | |||||
| IsLatestVersion string //是否是最新版本,1是,0否 | |||||
| CommitID string //提交的仓库代码id | |||||
| PreVersionName string //父版本名称 | |||||
| ComputeResource string //计算资源,例如npu | |||||
| EngineID int64 //引擎id | |||||
| TrainUrl string //输出的obs路径 | |||||
| BranchName string //分支名称 | |||||
| Parameters string //传给modelarts的param参数 | |||||
| BootFile string //启动文件 | |||||
| DataUrl string //数据集的obs路径 | |||||
| LogUrl string //日志输出的obs路径 | |||||
| PreVersionId int64 //父版本的版本id | |||||
| FlavorCode string //modelarts上的规格id | |||||
| Description string //描述 | |||||
| WorkServerNumber int //节点数 | |||||
| FlavorName string //规格名称 | |||||
| EngineName string //引擎名称 | |||||
| TotalVersionCount int //任务的所有版本数量,包括删除的 | |||||
| User *User `xorm:"-"` | User *User `xorm:"-"` | ||||
| Repo *Repository `xorm:"-"` | Repo *Repository `xorm:"-"` | ||||
| @@ -150,13 +170,16 @@ type CloudbrainsOptions struct { | |||||
| ListOptions | ListOptions | ||||
| RepoID int64 // include all repos if empty | RepoID int64 // include all repos if empty | ||||
| UserID int64 | UserID int64 | ||||
| JobID int64 | |||||
| JobID string | |||||
| SortType string | SortType string | ||||
| CloudbrainIDs []int64 | CloudbrainIDs []int64 | ||||
| // JobStatus CloudbrainStatus | // JobStatus CloudbrainStatus | ||||
| Type int | |||||
| JobType string | |||||
| Type int | |||||
| JobType string | |||||
| VersionName string | |||||
| IsLatestVersion string | |||||
| } | } | ||||
| type TaskPod struct { | type TaskPod struct { | ||||
| TaskRoleStatus struct { | TaskRoleStatus struct { | ||||
| Name string `json:"name"` | Name string `json:"name"` | ||||
| @@ -579,20 +602,33 @@ type Config struct { | |||||
| BootFileUrl string `json:"boot_file_url"` //训练作业的代码启动文件,需要在代码目录下 | BootFileUrl string `json:"boot_file_url"` //训练作业的代码启动文件,需要在代码目录下 | ||||
| Parameter []Parameter `json:"parameter"` | Parameter []Parameter `json:"parameter"` | ||||
| DataUrl string `json:"data_url"` //训练作业需要的数据集OBS路径URL | DataUrl string `json:"data_url"` //训练作业需要的数据集OBS路径URL | ||||
| //DatasetID string `json:"dataset_id"` | |||||
| //DataVersionID string `json:"dataset_version_id"` | |||||
| //DataSource []DataSource `json:"data_source"` | |||||
| //SpecID int64 `json:"spec_id"` | |||||
| EngineID int64 `json:"engine_id"` | |||||
| //ModelID int64 `json:"model_id"` | |||||
| TrainUrl string `json:"train_url"` //训练作业的输出文件OBS路径URL | |||||
| LogUrl string `json:"log_url"` | |||||
| EngineID int64 `json:"engine_id"` | |||||
| TrainUrl string `json:"train_url"` //训练作业的输出文件OBS路径URL | |||||
| LogUrl string `json:"log_url"` | |||||
| //UserImageUrl string `json:"user_image_url"` | //UserImageUrl string `json:"user_image_url"` | ||||
| //UserCommand string `json:"user_command"` | //UserCommand string `json:"user_command"` | ||||
| CreateVersion bool `json:"create_version"` | |||||
| //Volumes []Volumes `json:"volumes"` | |||||
| Flavor Flavor `json:"flavor"` | |||||
| PoolID string `json:"pool_id"` | |||||
| CreateVersion bool `json:"create_version"` | |||||
| Flavor Flavor `json:"flavor"` | |||||
| PoolID string `json:"pool_id"` | |||||
| } | |||||
| type CreateTrainJobVersionParams struct { | |||||
| Description string `json:"job_desc"` | |||||
| Config TrainJobVersionConfig `json:"config"` | |||||
| } | |||||
| type TrainJobVersionConfig struct { | |||||
| WorkServerNum int `json:"worker_server_num"` | |||||
| AppUrl string `json:"app_url"` //训练作业的代码目录 | |||||
| BootFileUrl string `json:"boot_file_url"` //训练作业的代码启动文件,需要在代码目录下 | |||||
| Parameter []Parameter `json:"parameter"` | |||||
| DataUrl string `json:"data_url"` //训练作业需要的数据集OBS路径URL | |||||
| EngineID int64 `json:"engine_id"` | |||||
| TrainUrl string `json:"train_url"` //训练作业的输出文件OBS路径URL | |||||
| LogUrl string `json:"log_url"` | |||||
| Flavor Flavor `json:"flavor"` | |||||
| PoolID string `json:"pool_id"` | |||||
| PreVersionId int64 `json:"pre_version_id"` | |||||
| } | } | ||||
| type CreateConfigParams struct { | type CreateConfigParams struct { | ||||
| @@ -603,20 +639,11 @@ type CreateConfigParams struct { | |||||
| BootFileUrl string `json:"boot_file_url"` //训练作业的代码启动文件,需要在代码目录下 | BootFileUrl string `json:"boot_file_url"` //训练作业的代码启动文件,需要在代码目录下 | ||||
| Parameter []Parameter `json:"parameter"` | Parameter []Parameter `json:"parameter"` | ||||
| DataUrl string `json:"data_url"` //训练作业需要的数据集OBS路径URL | DataUrl string `json:"data_url"` //训练作业需要的数据集OBS路径URL | ||||
| //DatasetID string `json:"dataset_id"` | |||||
| //DataVersionID string `json:"dataset_version_id"` | |||||
| //DataSource []DataSource `json:"data_source"` | |||||
| //SpecID int64 `json:"spec_id"` | |||||
| EngineID int64 `json:"engine_id"` | |||||
| //ModelID int64 `json:"model_id"` | |||||
| TrainUrl string `json:"train_url"` //训练作业的输出文件OBS路径URL | |||||
| LogUrl string `json:"log_url"` | |||||
| //UserImageUrl string `json:"user_image_url"` | |||||
| //UserCommand string `json:"user_command"` | |||||
| //CreateVersion bool `json:"create_version"` | |||||
| //Volumes []Volumes `json:"volumes"` | |||||
| Flavor Flavor `json:"flavor"` | |||||
| PoolID string `json:"pool_id"` | |||||
| EngineID int64 `json:"engine_id"` | |||||
| TrainUrl string `json:"train_url"` //训练作业的输出文件OBS路径URL | |||||
| LogUrl string `json:"log_url"` | |||||
| Flavor Flavor `json:"flavor"` | |||||
| PoolID string `json:"pool_id"` | |||||
| } | } | ||||
| type Parameter struct { | type Parameter struct { | ||||
| @@ -730,18 +757,10 @@ type GetConfigResult struct { | |||||
| BootFileUrl string `json:"boot_file_url"` //训练作业的代码启动文件,需要在代码目录下 | BootFileUrl string `json:"boot_file_url"` //训练作业的代码启动文件,需要在代码目录下 | ||||
| Parameter []Parameter `json:"parameter"` | Parameter []Parameter `json:"parameter"` | ||||
| DataUrl string `json:"data_url"` //训练作业需要的数据集OBS路径URL | DataUrl string `json:"data_url"` //训练作业需要的数据集OBS路径URL | ||||
| //DatasetID string `json:"dataset_id"` | |||||
| //DataVersionID string `json:"dataset_version_id"` | |||||
| //DataSource []DataSource `json:"data_source"` | |||||
| //SpecID int64 `json:"spec_id"` | |||||
| EngineID int64 `json:"engine_id"` | |||||
| //ModelID int64 `json:"model_id"` | |||||
| TrainUrl string `json:"train_url"` //训练作业的输出文件OBS路径URL | |||||
| LogUrl string `json:"log_url"` | |||||
| //UserImageUrl string `json:"user_image_url"` | |||||
| //UserCommand string `json:"user_command"` | |||||
| //CreateVersion bool `json:"create_version"` | |||||
| //Volumes []Volumes `json:"volumes"` | |||||
| EngineID int64 `json:"engine_id"` | |||||
| TrainUrl string `json:"train_url"` //训练作业的输出文件OBS路径URL | |||||
| LogUrl string `json:"log_url"` | |||||
| Flavor Flavor `json:"flavor"` | Flavor Flavor `json:"flavor"` | ||||
| PoolID string `json:"pool_id"` | PoolID string `json:"pool_id"` | ||||
| } | } | ||||
| @@ -772,25 +791,18 @@ type GetTrainJobResult struct { | |||||
| BootFileUrl string `json:"boot_file_url"` //训练作业的代码启动文件,需要在代码目录下 | BootFileUrl string `json:"boot_file_url"` //训练作业的代码启动文件,需要在代码目录下 | ||||
| Parameter []Parameter `json:"parameter"` | Parameter []Parameter `json:"parameter"` | ||||
| DataUrl string `json:"data_url"` //训练作业需要的数据集OBS路径URL | DataUrl string `json:"data_url"` //训练作业需要的数据集OBS路径URL | ||||
| //DatasetID string `json:"dataset_id"` | |||||
| //DataVersionID string `json:"dataset_version_id"` | |||||
| //DataSource []DataSource `json:"data_source"` | |||||
| //SpecID int64 `json:"spec_id"` | |||||
| EngineID int64 `json:"engine_id"` | |||||
| EngineName string `json:"engine_name"` | |||||
| EngineVersion string `json:"engine_version"` | |||||
| //ModelID int64 `json:"model_id"` | |||||
| TrainUrl string `json:"train_url"` //训练作业的输出文件OBS路径URL | |||||
| LogUrl string `json:"log_url"` | |||||
| //UserImageUrl string `json:"user_image_url"` | |||||
| //UserCommand string `json:"user_command"` | |||||
| //Volumes []Volumes `json:"volumes"` | |||||
| Flavor Flavor `json:"flavor"` | |||||
| PoolID string `json:"pool_id"` | |||||
| PoolName string `json:"pool_name"` | |||||
| NasMountPath string `json:"nas_mount_path"` | |||||
| NasShareAddr string `json:"nas_share_addr"` | |||||
| DatasetName string | |||||
| EngineID int64 `json:"engine_id"` | |||||
| EngineName string `json:"engine_name"` | |||||
| EngineVersion string `json:"engine_version"` | |||||
| TrainUrl string `json:"train_url"` //训练作业的输出文件OBS路径URL | |||||
| LogUrl string `json:"log_url"` | |||||
| Flavor Flavor `json:"flavor"` | |||||
| PoolID string `json:"pool_id"` | |||||
| PoolName string `json:"pool_name"` | |||||
| NasMountPath string `json:"nas_mount_path"` | |||||
| NasShareAddr string `json:"nas_share_addr"` | |||||
| DatasetName string | |||||
| ModelMetricList string `json:"model_metric_list"` //列表里包含f1_score,recall,precision,accuracy,若有的话 | |||||
| } | } | ||||
| type GetTrainJobLogResult struct { | type GetTrainJobLogResult struct { | ||||
| @@ -837,7 +849,7 @@ func Cloudbrains(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, error) { | |||||
| ) | ) | ||||
| } | } | ||||
| if (opts.JobID) > 0 { | |||||
| if (opts.JobID) != "" { | |||||
| cond = cond.And( | cond = cond.And( | ||||
| builder.Eq{"cloudbrain.job_id": opts.JobID}, | builder.Eq{"cloudbrain.job_id": opts.JobID}, | ||||
| ) | ) | ||||
| @@ -855,16 +867,11 @@ func Cloudbrains(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, error) { | |||||
| ) | ) | ||||
| } | } | ||||
| // switch opts.JobStatus { | |||||
| // case JobWaiting: | |||||
| // cond.And(builder.Eq{"cloudbrain.status": int(JobWaiting)}) | |||||
| // case JobFailed: | |||||
| // cond.And(builder.Eq{"cloudbrain.status": int(JobFailed)}) | |||||
| // case JobStopped: | |||||
| // cond.And(builder.Eq{"cloudbrain.status": int(JobStopped)}) | |||||
| // case JobSucceeded: | |||||
| // cond.And(builder.Eq{"cloudbrain.status": int(JobSucceeded)}) | |||||
| // } | |||||
| if (opts.IsLatestVersion) != "" { | |||||
| cond = cond.And( | |||||
| builder.Eq{"cloudbrain.is_latest_version": opts.IsLatestVersion}, | |||||
| ) | |||||
| } | |||||
| if len(opts.CloudbrainIDs) > 0 { | if len(opts.CloudbrainIDs) > 0 { | ||||
| cond = cond.And(builder.In("cloudbrain.id", opts.CloudbrainIDs)) | cond = cond.And(builder.In("cloudbrain.id", opts.CloudbrainIDs)) | ||||
| @@ -892,16 +899,79 @@ func Cloudbrains(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, error) { | |||||
| Find(&cloudbrains); err != nil { | Find(&cloudbrains); err != nil { | ||||
| return nil, 0, fmt.Errorf("Find: %v", err) | return nil, 0, fmt.Errorf("Find: %v", err) | ||||
| } | } | ||||
| sess.Close() | |||||
| return cloudbrains, count, nil | return cloudbrains, count, nil | ||||
| } | } | ||||
| func CloudbrainsVersionList(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int, error) { | |||||
| sess := x.NewSession() | |||||
| defer sess.Close() | |||||
| var cond = builder.NewCond() | |||||
| if opts.RepoID > 0 { | |||||
| cond = cond.And( | |||||
| builder.Eq{"cloudbrain.repo_id": opts.RepoID}, | |||||
| ) | |||||
| } | |||||
| if opts.UserID > 0 { | |||||
| cond = cond.And( | |||||
| builder.Eq{"cloudbrain.user_id": opts.UserID}, | |||||
| ) | |||||
| } | |||||
| if (opts.Type) >= 0 { | |||||
| cond = cond.And( | |||||
| builder.Eq{"cloudbrain.type": opts.Type}, | |||||
| ) | |||||
| } | |||||
| if (opts.JobID) != "" { | |||||
| cond = cond.And( | |||||
| builder.Eq{"cloudbrain.job_id": opts.JobID}, | |||||
| ) | |||||
| } | |||||
| if (opts.JobType) != "" { | |||||
| cond = cond.And( | |||||
| builder.Eq{"cloudbrain.job_type": opts.JobType}, | |||||
| ) | |||||
| } | |||||
| if len(opts.CloudbrainIDs) > 0 { | |||||
| cond = cond.And(builder.In("cloudbrain.id", opts.CloudbrainIDs)) | |||||
| } | |||||
| count, err := sess.Where(cond).Count(new(Cloudbrain)) | |||||
| if err != nil { | |||||
| return nil, 0, fmt.Errorf("Count: %v", err) | |||||
| } | |||||
| if opts.Page >= 0 && opts.PageSize > 0 { | |||||
| var start int | |||||
| if opts.Page == 0 { | |||||
| start = 0 | |||||
| } else { | |||||
| start = (opts.Page - 1) * opts.PageSize | |||||
| } | |||||
| sess.Limit(opts.PageSize, start) | |||||
| } | |||||
| sess.OrderBy("cloudbrain.created_unix DESC") | |||||
| cloudbrains := make([]*CloudbrainInfo, 0, setting.UI.IssuePagingNum) | |||||
| if err := sess.Table(&Cloudbrain{}).Where(cond). | |||||
| Join("left", "`user`", "cloudbrain.user_id = `user`.id"). | |||||
| Find(&cloudbrains); err != nil { | |||||
| return nil, 0, fmt.Errorf("Find: %v", err) | |||||
| } | |||||
| return cloudbrains, int(count), nil | |||||
| } | |||||
| func CreateCloudbrain(cloudbrain *Cloudbrain) (err error) { | func CreateCloudbrain(cloudbrain *Cloudbrain) (err error) { | ||||
| if _, err = x.Insert(cloudbrain); err != nil { | if _, err = x.Insert(cloudbrain); err != nil { | ||||
| return err | return err | ||||
| } | } | ||||
| return nil | return nil | ||||
| } | } | ||||
| @@ -925,6 +995,16 @@ func GetCloudbrainByJobID(jobID string) (*Cloudbrain, error) { | |||||
| return getRepoCloudBrain(cb) | return getRepoCloudBrain(cb) | ||||
| } | } | ||||
| func GetCloudbrainByJobIDAndVersionName(jobID string, versionName string) (*Cloudbrain, error) { | |||||
| cb := &Cloudbrain{JobID: jobID, VersionName: versionName} | |||||
| return getRepoCloudBrain(cb) | |||||
| } | |||||
| func GetCloudbrainByJobIDAndIsLatestVersion(jobID string, isLatestVersion string) (*Cloudbrain, error) { | |||||
| cb := &Cloudbrain{JobID: jobID, IsLatestVersion: isLatestVersion} | |||||
| return getRepoCloudBrain(cb) | |||||
| } | |||||
| func GetCloudbrainsNeededStopByUserID(userID int64) ([]*Cloudbrain, error) { | func GetCloudbrainsNeededStopByUserID(userID int64) ([]*Cloudbrain, error) { | ||||
| cloudBrains := make([]*Cloudbrain, 0) | cloudBrains := make([]*Cloudbrain, 0) | ||||
| err := x.Cols("job_id", "status", "type").Where("user_id=? AND status !=?", userID, string(JobStopped)).Find(&cloudBrains) | err := x.Cols("job_id", "status", "type").Where("user_id=? AND status !=?", userID, string(JobStopped)).Find(&cloudBrains) | ||||
| @@ -949,6 +1029,12 @@ func SetTrainJobStatusByJobID(jobID string, status string, duration int64, train | |||||
| return | return | ||||
| } | } | ||||
| func SetVersionCountAndLatestVersion(jobID string, versionName string, versionCount int, isLatestVersion string, totalVersionCount int) (err error) { | |||||
| cb := &Cloudbrain{JobID: jobID, VersionName: versionName, VersionCount: versionCount, IsLatestVersion: isLatestVersion, TotalVersionCount: totalVersionCount} | |||||
| _, err = x.Cols("version_Count", "is_latest_version", "total_version_count").Where("cloudbrain.job_id=? AND cloudbrain.version_name=?", jobID, versionName).Update(cb) | |||||
| return | |||||
| } | |||||
| func UpdateJob(job *Cloudbrain) error { | func UpdateJob(job *Cloudbrain) error { | ||||
| return updateJob(x, job) | return updateJob(x, job) | ||||
| } | } | ||||
| @@ -960,16 +1046,16 @@ func updateJob(e Engine, job *Cloudbrain) error { | |||||
| return err | return err | ||||
| } | } | ||||
| // func UpdateTrainJob(job *CloudbrainInfo) error { | |||||
| // return updateTrainJob(x, job) | |||||
| // } | |||||
| func UpdateTrainJobVersion(job *Cloudbrain) error { | |||||
| return updateJobTrainVersion(x, job) | |||||
| } | |||||
| // func updateTrainJob(e Engine, job *CloudbrainInfo) error { | |||||
| // var sess *xorm.Session | |||||
| // sess = e.Where("job_id = ?", job.Cloudbrain.JobID) | |||||
| // _, err := sess.Cols("status", "container_id", "container_ip").Update(job) | |||||
| // return err | |||||
| // } | |||||
| func updateJobTrainVersion(e Engine, job *Cloudbrain) error { | |||||
| var sess *xorm.Session | |||||
| sess = e.Where("job_id = ? AND version_name=?", job.JobID, job.VersionName) | |||||
| _, err := sess.Cols("status", "train_job_duration").Update(job) | |||||
| return err | |||||
| } | |||||
| func DeleteJob(job *Cloudbrain) error { | func DeleteJob(job *Cloudbrain) error { | ||||
| return deleteJob(x, job) | return deleteJob(x, job) | ||||
| @@ -19,7 +19,7 @@ type CreateModelArtsNotebookForm struct { | |||||
| JobName string `form:"job_name" binding:"Required"` | JobName string `form:"job_name" binding:"Required"` | ||||
| Attachment string `form:"attachment"` | Attachment string `form:"attachment"` | ||||
| Description string `form:"description"` | Description string `form:"description"` | ||||
| Flavor string `form:"flavor"` | |||||
| Flavor string `form:"flavor"` | |||||
| } | } | ||||
| func (f *CreateModelArtsNotebookForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { | func (f *CreateModelArtsNotebookForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { | ||||
| @@ -39,6 +39,10 @@ type CreateModelArtsTrainJobForm struct { | |||||
| IsSaveParam string `form:"is_save_para"` | IsSaveParam string `form:"is_save_para"` | ||||
| ParameterTemplateName string `form:"parameter_template_name"` | ParameterTemplateName string `form:"parameter_template_name"` | ||||
| PrameterDescription string `form:"parameter_description"` | PrameterDescription string `form:"parameter_description"` | ||||
| BranchName string `form:"branch_name" binding:"Required"` | |||||
| VersionName string `form:"version_name" binding:"Required"` | |||||
| FlavorName string `form:"flaver_names" binding:"Required"` | |||||
| EngineName string `form:"engine_names" binding:"Required"` | |||||
| } | } | ||||
| func (f *CreateModelArtsTrainJobForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { | func (f *CreateModelArtsTrainJobForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { | ||||
| @@ -2,6 +2,7 @@ package modelarts | |||||
| import ( | import ( | ||||
| "encoding/json" | "encoding/json" | ||||
| "fmt" | |||||
| "path" | "path" | ||||
| "strconv" | "strconv" | ||||
| @@ -35,19 +36,24 @@ const ( | |||||
| // "{\"code\":\"modelarts.bm.910.arm.public.4\",\"value\":\"Ascend : 4 * Ascend 910 CPU:96 核 1024GiB\"}," + | // "{\"code\":\"modelarts.bm.910.arm.public.4\",\"value\":\"Ascend : 4 * Ascend 910 CPU:96 核 1024GiB\"}," + | ||||
| // "{\"code\":\"modelarts.bm.910.arm.public.1\",\"value\":\"Ascend : 1 * Ascend 910 CPU:24 核 256GiB\"}" + | // "{\"code\":\"modelarts.bm.910.arm.public.1\",\"value\":\"Ascend : 1 * Ascend 910 CPU:24 核 256GiB\"}" + | ||||
| // "]}" | // "]}" | ||||
| CodePath = "/code/" | |||||
| OutputPath = "/output/" | |||||
| LogPath = "/log/" | |||||
| JobPath = "/job/" | |||||
| OrderDesc = "desc" //向下查询 | |||||
| OrderAsc = "asc" //向上查询 | |||||
| Lines = 20 | |||||
| TrainUrl = "train_url" | |||||
| DataUrl = "data_url" | |||||
| PerPage = 10 | |||||
| SortByCreateTime = "create_time" | |||||
| ConfigTypeCustom = "custom" | |||||
| CodePath = "/code/" | |||||
| OutputPath = "/output/" | |||||
| LogPath = "/log/" | |||||
| JobPath = "/job/" | |||||
| OrderDesc = "desc" //向下查询 | |||||
| OrderAsc = "asc" //向上查询 | |||||
| Lines = 500 | |||||
| TrainUrl = "train_url" | |||||
| DataUrl = "data_url" | |||||
| PerPage = 10 | |||||
| IsLatestVersion = "1" | |||||
| NotLatestVersion = "0" | |||||
| ComputeResource = "NPU" | |||||
| VersionCount = 1 | |||||
| SortByCreateTime = "create_time" | |||||
| ConfigTypeCustom = "custom" | |||||
| TotalVersionCount = 1 | |||||
| ) | ) | ||||
| var ( | var ( | ||||
| @@ -56,19 +62,55 @@ var ( | |||||
| ) | ) | ||||
| type GenerateTrainJobReq struct { | type GenerateTrainJobReq struct { | ||||
| JobName string | |||||
| Uuid string | |||||
| Description string | |||||
| CodeObsPath string | |||||
| BootFile string | |||||
| DataUrl string | |||||
| TrainUrl string | |||||
| FlavorCode string | |||||
| LogUrl string | |||||
| PoolID string | |||||
| WorkServerNumber int | |||||
| EngineID int64 | |||||
| Parameters []models.Parameter | |||||
| JobName string | |||||
| Uuid string | |||||
| Description string | |||||
| CodeObsPath string | |||||
| BootFile string | |||||
| BootFileUrl string | |||||
| DataUrl string | |||||
| TrainUrl string | |||||
| FlavorCode string | |||||
| LogUrl string | |||||
| PoolID string | |||||
| WorkServerNumber int | |||||
| EngineID int64 | |||||
| Parameters []models.Parameter | |||||
| CommitID string | |||||
| IsLatestVersion string | |||||
| Params string | |||||
| BranchName string | |||||
| PreVersionId int64 | |||||
| PreVersionName string | |||||
| FlavorName string | |||||
| VersionCount int | |||||
| EngineName string | |||||
| TotalVersionCount int | |||||
| } | |||||
| type GenerateTrainJobVersionReq struct { | |||||
| JobName string | |||||
| Uuid string | |||||
| Description string | |||||
| CodeObsPath string | |||||
| BootFile string | |||||
| BootFileUrl string | |||||
| DataUrl string | |||||
| TrainUrl string | |||||
| FlavorCode string | |||||
| LogUrl string | |||||
| PoolID string | |||||
| WorkServerNumber int | |||||
| EngineID int64 | |||||
| Parameters []models.Parameter | |||||
| Params string | |||||
| PreVersionId int64 | |||||
| CommitID string | |||||
| BranchName string | |||||
| FlavorName string | |||||
| EngineName string | |||||
| PreVersionName string | |||||
| TotalVersionCount int | |||||
| } | } | ||||
| type VersionInfo struct { | type VersionInfo struct { | ||||
| @@ -99,6 +141,22 @@ type ResourcePool struct { | |||||
| } `json:"resource_pool"` | } `json:"resource_pool"` | ||||
| } | } | ||||
| // type Parameter struct { | |||||
| // Label string `json:"label"` | |||||
| // Value string `json:"value"` | |||||
| // } | |||||
| // type Parameters struct { | |||||
| // Parameter []Parameter `json:"parameter"` | |||||
| // } | |||||
| type Parameters struct { | |||||
| Parameter []struct { | |||||
| Label string `json:"label"` | |||||
| Value string `json:"value"` | |||||
| } `json:"parameter"` | |||||
| } | |||||
| func GenerateTask(ctx *context.Context, jobName, uuid, description, flavor string) error { | func GenerateTask(ctx *context.Context, jobName, uuid, description, flavor string) error { | ||||
| var dataActualPath string | var dataActualPath string | ||||
| if uuid != "" { | if uuid != "" { | ||||
| @@ -170,14 +228,14 @@ func GenerateTask(ctx *context.Context, jobName, uuid, description, flavor strin | |||||
| return nil | return nil | ||||
| } | } | ||||
| func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) error { | |||||
| func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error) { | |||||
| jobResult, err := createTrainJob(models.CreateTrainJobParams{ | jobResult, err := createTrainJob(models.CreateTrainJobParams{ | ||||
| JobName: req.JobName, | JobName: req.JobName, | ||||
| Description: req.Description, | Description: req.Description, | ||||
| Config: models.Config{ | Config: models.Config{ | ||||
| WorkServerNum: req.WorkServerNumber, | WorkServerNum: req.WorkServerNumber, | ||||
| AppUrl: req.CodeObsPath, | AppUrl: req.CodeObsPath, | ||||
| BootFileUrl: req.BootFile, | |||||
| BootFileUrl: req.BootFileUrl, | |||||
| DataUrl: req.DataUrl, | DataUrl: req.DataUrl, | ||||
| EngineID: req.EngineID, | EngineID: req.EngineID, | ||||
| TrainUrl: req.TrainUrl, | TrainUrl: req.TrainUrl, | ||||
| @@ -198,21 +256,38 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) error { | |||||
| attach, err := models.GetAttachmentByUUID(req.Uuid) | attach, err := models.GetAttachmentByUUID(req.Uuid) | ||||
| if err != nil { | if err != nil { | ||||
| log.Error("GetAttachmentByUUID(%s) failed:%v", strconv.FormatInt(jobResult.JobID, 10), err.Error()) | log.Error("GetAttachmentByUUID(%s) failed:%v", strconv.FormatInt(jobResult.JobID, 10), err.Error()) | ||||
| return nil | |||||
| return err | |||||
| } | } | ||||
| err = models.CreateCloudbrain(&models.Cloudbrain{ | err = models.CreateCloudbrain(&models.Cloudbrain{ | ||||
| Status: TransTrainJobStatus(jobResult.Status), | |||||
| UserID: ctx.User.ID, | |||||
| RepoID: ctx.Repo.Repository.ID, | |||||
| JobID: strconv.FormatInt(jobResult.JobID, 10), | |||||
| JobName: req.JobName, | |||||
| JobType: string(models.JobTypeTrain), | |||||
| Type: models.TypeCloudBrainTwo, | |||||
| VersionID: jobResult.VersionID, | |||||
| VersionName: jobResult.VersionName, | |||||
| Uuid: req.Uuid, | |||||
| DatasetName: attach.Name, | |||||
| Status: TransTrainJobStatus(jobResult.Status), | |||||
| UserID: ctx.User.ID, | |||||
| RepoID: ctx.Repo.Repository.ID, | |||||
| JobID: strconv.FormatInt(jobResult.JobID, 10), | |||||
| JobName: req.JobName, | |||||
| JobType: string(models.JobTypeTrain), | |||||
| Type: models.TypeCloudBrainTwo, | |||||
| VersionID: jobResult.VersionID, | |||||
| VersionName: jobResult.VersionName, | |||||
| Uuid: req.Uuid, | |||||
| DatasetName: attach.Name, | |||||
| CommitID: req.CommitID, | |||||
| IsLatestVersion: req.IsLatestVersion, | |||||
| ComputeResource: ComputeResource, | |||||
| EngineID: req.EngineID, | |||||
| TrainUrl: req.TrainUrl, | |||||
| BranchName: req.BranchName, | |||||
| Parameters: req.Params, | |||||
| BootFile: req.BootFile, | |||||
| DataUrl: req.DataUrl, | |||||
| LogUrl: req.LogUrl, | |||||
| FlavorCode: req.FlavorCode, | |||||
| Description: req.Description, | |||||
| WorkServerNumber: req.WorkServerNumber, | |||||
| FlavorName: req.FlavorName, | |||||
| EngineName: req.EngineName, | |||||
| VersionCount: req.VersionCount, | |||||
| TotalVersionCount: req.TotalVersionCount, | |||||
| }) | }) | ||||
| if err != nil { | if err != nil { | ||||
| @@ -223,6 +298,96 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) error { | |||||
| return nil | return nil | ||||
| } | } | ||||
| func GenerateTrainJobVersion(ctx *context.Context, req *GenerateTrainJobReq, jobId string) (err error) { | |||||
| jobResult, err := createTrainJobVersion(models.CreateTrainJobVersionParams{ | |||||
| Description: req.Description, | |||||
| Config: models.TrainJobVersionConfig{ | |||||
| WorkServerNum: req.WorkServerNumber, | |||||
| AppUrl: req.CodeObsPath, | |||||
| BootFileUrl: req.BootFileUrl, | |||||
| DataUrl: req.DataUrl, | |||||
| EngineID: req.EngineID, | |||||
| TrainUrl: req.TrainUrl, | |||||
| LogUrl: req.LogUrl, | |||||
| PoolID: req.PoolID, | |||||
| Flavor: models.Flavor{ | |||||
| Code: req.FlavorCode, | |||||
| }, | |||||
| Parameter: req.Parameters, | |||||
| PreVersionId: req.PreVersionId, | |||||
| }, | |||||
| }, jobId) | |||||
| if err != nil { | |||||
| log.Error("CreateJob failed: %v", err.Error()) | |||||
| return err | |||||
| } | |||||
| attach, err := models.GetAttachmentByUUID(req.Uuid) | |||||
| if err != nil { | |||||
| log.Error("GetAttachmentByUUID(%s) failed:%v", strconv.FormatInt(jobResult.JobID, 10), err.Error()) | |||||
| return err | |||||
| } | |||||
| repo := ctx.Repo.Repository | |||||
| VersionTaskList, VersionListCount, err := models.CloudbrainsVersionList(&models.CloudbrainsOptions{ | |||||
| RepoID: repo.ID, | |||||
| Type: models.TypeCloudBrainTwo, | |||||
| JobType: string(models.JobTypeTrain), | |||||
| JobID: strconv.FormatInt(jobResult.JobID, 10), | |||||
| }) | |||||
| if err != nil { | |||||
| ctx.ServerError("Cloudbrain", err) | |||||
| return err | |||||
| } | |||||
| //将当前版本的isLatestVersion设置为"1"和任务数量更新,任务数量包括当前版本数VersionCount和历史创建的总版本数TotalVersionCount | |||||
| err = models.CreateCloudbrain(&models.Cloudbrain{ | |||||
| Status: TransTrainJobStatus(jobResult.Status), | |||||
| UserID: ctx.User.ID, | |||||
| RepoID: ctx.Repo.Repository.ID, | |||||
| JobID: strconv.FormatInt(jobResult.JobID, 10), | |||||
| JobName: req.JobName, | |||||
| JobType: string(models.JobTypeTrain), | |||||
| Type: models.TypeCloudBrainTwo, | |||||
| VersionID: jobResult.VersionID, | |||||
| VersionName: jobResult.VersionName, | |||||
| Uuid: req.Uuid, | |||||
| DatasetName: attach.Name, | |||||
| CommitID: req.CommitID, | |||||
| IsLatestVersion: req.IsLatestVersion, | |||||
| PreVersionName: req.PreVersionName, | |||||
| ComputeResource: ComputeResource, | |||||
| EngineID: req.EngineID, | |||||
| TrainUrl: req.TrainUrl, | |||||
| BranchName: req.BranchName, | |||||
| Parameters: req.Params, | |||||
| BootFile: req.BootFile, | |||||
| DataUrl: req.DataUrl, | |||||
| LogUrl: req.LogUrl, | |||||
| PreVersionId: req.PreVersionId, | |||||
| FlavorCode: req.FlavorCode, | |||||
| Description: req.Description, | |||||
| WorkServerNumber: req.WorkServerNumber, | |||||
| FlavorName: req.FlavorName, | |||||
| EngineName: req.EngineName, | |||||
| TotalVersionCount: VersionTaskList[0].TotalVersionCount + 1, | |||||
| VersionCount: VersionListCount + 1, | |||||
| }) | |||||
| if err != nil { | |||||
| log.Error("CreateCloudbrain(%s) failed:%v", req.JobName, err.Error()) | |||||
| return err | |||||
| } | |||||
| //将训练任务的上一版本的isLatestVersion设置为"0" | |||||
| err = models.SetVersionCountAndLatestVersion(strconv.FormatInt(jobResult.JobID, 10), VersionTaskList[0].VersionName, VersionCount, NotLatestVersion, TotalVersionCount) | |||||
| if err != nil { | |||||
| ctx.ServerError("Update IsLatestVersion failed", err) | |||||
| return err | |||||
| } | |||||
| return err | |||||
| } | |||||
| func TransTrainJobStatus(status int) string { | func TransTrainJobStatus(status int) string { | ||||
| switch status { | switch status { | ||||
| case 0: | case 0: | ||||
| @@ -273,6 +438,10 @@ func TransTrainJobStatus(status int) string { | |||||
| default: | default: | ||||
| return strconv.Itoa(status) | return strconv.Itoa(status) | ||||
| } | } | ||||
| } | |||||
| return "" | |||||
| func GetVersionOutputPathByTotalVersionCount(TotalVersionCount int) (VersionOutputPath string) { | |||||
| talVersionCountToString := fmt.Sprintf("%04d", TotalVersionCount) | |||||
| VersionOutputPath = "V" + talVersionCountToString | |||||
| return VersionOutputPath | |||||
| } | } | ||||
| @@ -366,6 +366,16 @@ sendjob: | |||||
| return &result, fmt.Errorf("json.Unmarshal failed(%s): %v", res.String(), err.Error()) | return &result, fmt.Errorf("json.Unmarshal failed(%s): %v", res.String(), err.Error()) | ||||
| } | } | ||||
| log.Error("createTrainJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | log.Error("createTrainJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | ||||
| BootFileErrorMsg := "Invalid OBS path '" + createJobParams.Config.BootFileUrl + "'." | |||||
| DataSetErrorMsg := "Invalid OBS path '" + createJobParams.Config.DataUrl + "'." | |||||
| if temp.ErrorMsg == BootFileErrorMsg { | |||||
| log.Error("启动文件错误!createTrainJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||||
| return &result, fmt.Errorf("启动文件错误!") | |||||
| } | |||||
| if temp.ErrorMsg == DataSetErrorMsg { | |||||
| log.Error("数据集错误!createTrainJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||||
| return &result, fmt.Errorf("数据集错误!") | |||||
| } | |||||
| return &result, fmt.Errorf("createTrainJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | return &result, fmt.Errorf("createTrainJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | ||||
| } | } | ||||
| @@ -377,6 +387,61 @@ sendjob: | |||||
| return &result, nil | return &result, nil | ||||
| } | } | ||||
| func createTrainJobVersion(createJobVersionParams models.CreateTrainJobVersionParams, jobID string) (*models.CreateTrainJobResult, error) { | |||||
| checkSetting() | |||||
| client := getRestyClient() | |||||
| var result models.CreateTrainJobResult | |||||
| retry := 0 | |||||
| sendjob: | |||||
| res, err := client.R(). | |||||
| SetHeader("Content-Type", "application/json"). | |||||
| SetAuthToken(TOKEN). | |||||
| SetBody(createJobVersionParams). | |||||
| SetResult(&result). | |||||
| Post(HOST + "/v1/" + setting.ProjectID + urlTrainJob + "/" + jobID + "/versions") | |||||
| if err != nil { | |||||
| return nil, fmt.Errorf("resty create train-job version: %s", err) | |||||
| } | |||||
| req, _ := json.Marshal(createJobVersionParams) | |||||
| log.Info("%s", req) | |||||
| if res.StatusCode() == http.StatusUnauthorized && retry < 1 { | |||||
| retry++ | |||||
| _ = getToken() | |||||
| goto sendjob | |||||
| } | |||||
| if res.StatusCode() != http.StatusOK { | |||||
| var temp models.ErrorResult | |||||
| if err = json.Unmarshal([]byte(res.String()), &temp); err != nil { | |||||
| log.Error("json.Unmarshal failed(%s): %v", res.String(), err.Error()) | |||||
| return &result, fmt.Errorf("json.Unmarshal failed(%s): %v", res.String(), err.Error()) | |||||
| } | |||||
| BootFileErrorMsg := "Invalid OBS path '" + createJobVersionParams.Config.BootFileUrl + "'." | |||||
| DataSetErrorMsg := "Invalid OBS path '" + createJobVersionParams.Config.DataUrl + "'." | |||||
| if temp.ErrorMsg == BootFileErrorMsg { | |||||
| log.Error("启动文件错误!createTrainJobVersion failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||||
| return &result, fmt.Errorf("启动文件错误!") | |||||
| } | |||||
| if temp.ErrorMsg == DataSetErrorMsg { | |||||
| log.Error("数据集错误!createTrainJobVersion failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||||
| return &result, fmt.Errorf("数据集错误!") | |||||
| } | |||||
| return &result, fmt.Errorf("createTrainJobVersion failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||||
| } | |||||
| if !result.IsSuccess { | |||||
| log.Error("createTrainJobVersion failed(%s): %s", result.ErrorCode, result.ErrorMsg) | |||||
| return &result, fmt.Errorf("createTrainJobVersion failed(%s): %s", result.ErrorCode, result.ErrorMsg) | |||||
| } | |||||
| return &result, nil | |||||
| } | |||||
| func GetResourceSpecs() (*models.GetResourceSpecsResult, error) { | func GetResourceSpecs() (*models.GetResourceSpecsResult, error) { | ||||
| checkSetting() | checkSetting() | ||||
| client := getRestyClient() | client := getRestyClient() | ||||
| @@ -768,3 +833,44 @@ sendjob: | |||||
| return &result, nil | return &result, nil | ||||
| } | } | ||||
| func DelTrainJobVersion(jobID string, versionID string) (*models.TrainJobResult, error) { | |||||
| checkSetting() | |||||
| client := getRestyClient() | |||||
| var result models.TrainJobResult | |||||
| retry := 0 | |||||
| sendjob: | |||||
| res, err := client.R(). | |||||
| SetAuthToken(TOKEN). | |||||
| SetResult(&result). | |||||
| Delete(HOST + "/v1/" + setting.ProjectID + urlTrainJob + "/" + jobID + "/versions/" + versionID) | |||||
| if err != nil { | |||||
| return &result, fmt.Errorf("resty DelTrainJobVersion: %v", err) | |||||
| } | |||||
| if res.StatusCode() == http.StatusUnauthorized && retry < 1 { | |||||
| retry++ | |||||
| _ = getToken() | |||||
| goto sendjob | |||||
| } | |||||
| if res.StatusCode() != http.StatusOK { | |||||
| var temp models.ErrorResult | |||||
| if err = json.Unmarshal([]byte(res.String()), &temp); err != nil { | |||||
| log.Error("json.Unmarshal failed(%s): %v", res.String(), err.Error()) | |||||
| return &result, fmt.Errorf("json.Unmarshal failed(%s): %v", res.String(), err.Error()) | |||||
| } | |||||
| log.Error("DelTrainJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||||
| return &result, fmt.Errorf("删除训练作业版本失败(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||||
| } | |||||
| if !result.IsSuccess { | |||||
| log.Error("DelTrainJob(%s) failed", jobID) | |||||
| return &result, fmt.Errorf("删除训练作业版本失败:%s", result.ErrorMsg) | |||||
| } | |||||
| return &result, nil | |||||
| } | |||||
| @@ -92,6 +92,7 @@ func NewFuncMap() []template.FuncMap { | |||||
| "Str2html": Str2html, | "Str2html": Str2html, | ||||
| "TimeSince": timeutil.TimeSince, | "TimeSince": timeutil.TimeSince, | ||||
| "TimeSinceUnix": timeutil.TimeSinceUnix, | "TimeSinceUnix": timeutil.TimeSinceUnix, | ||||
| "TimeSinceUnix1": timeutil.TimeSinceUnix1, | |||||
| "RawTimeSince": timeutil.RawTimeSince, | "RawTimeSince": timeutil.RawTimeSince, | ||||
| "FileSize": base.FileSize, | "FileSize": base.FileSize, | ||||
| "PrettyNumber": base.PrettyNumber, | "PrettyNumber": base.PrettyNumber, | ||||
| @@ -340,6 +341,7 @@ func NewTextFuncMap() []texttmpl.FuncMap { | |||||
| }, | }, | ||||
| "TimeSince": timeutil.TimeSince, | "TimeSince": timeutil.TimeSince, | ||||
| "TimeSinceUnix": timeutil.TimeSinceUnix, | "TimeSinceUnix": timeutil.TimeSinceUnix, | ||||
| "TimeSinceUnix1": timeutil.TimeSinceUnix1, | |||||
| "RawTimeSince": timeutil.RawTimeSince, | "RawTimeSince": timeutil.RawTimeSince, | ||||
| "DateFmtLong": func(t time.Time) string { | "DateFmtLong": func(t time.Time) string { | ||||
| return t.Format(time.RFC1123Z) | return t.Format(time.RFC1123Z) | ||||
| @@ -162,3 +162,8 @@ func htmlTimeSinceUnix(then, now TimeStamp, lang string) template.HTML { | |||||
| then.FormatInLocation(GetTimeFormat(lang), setting.DefaultUILocation), | then.FormatInLocation(GetTimeFormat(lang), setting.DefaultUILocation), | ||||
| timeSinceUnix(int64(then), int64(now), lang))) | timeSinceUnix(int64(then), int64(now), lang))) | ||||
| } | } | ||||
| func TimeSinceUnix1(then TimeStamp) string { | |||||
| format := time.Unix(int64(then), 0).Format("2006-01-02 15:04:05") | |||||
| return format | |||||
| } | |||||
| @@ -823,7 +823,11 @@ modelarts.train_job.new_train=New Train Task | |||||
| modelarts.train_job.config=Configuration information | modelarts.train_job.config=Configuration information | ||||
| modelarts.train_job.new=New train Task | modelarts.train_job.new=New train Task | ||||
| modelarts.train_job.new_place=The description should not exceed 256 characters | modelarts.train_job.new_place=The description should not exceed 256 characters | ||||
| modelarts.modify=Modify | |||||
| modelarts.current_version=Current version | |||||
| modelarts.parent_version=Parent Version | |||||
| modelarts.run_version=Run Version | |||||
| modelarts.train_job.compute_node=Compute Node | |||||
| modelarts.train_job.basic_info=Basic Info | modelarts.train_job.basic_info=Basic Info | ||||
| @@ -844,6 +848,8 @@ modelarts.train_job.AI_driver=AI Engine | |||||
| modelarts.train_job.start_file=Start File | modelarts.train_job.start_file=Start File | ||||
| modelarts.train_job.boot_file_helper=The startup file is the entry file that your program executes, and it must be a file ending in .py | modelarts.train_job.boot_file_helper=The startup file is the entry file that your program executes, and it must be a file ending in .py | ||||
| modelarts.train_job.dataset=Dataset | modelarts.train_job.dataset=Dataset | ||||
| modelarts.code_version = Code Version | |||||
| modelarts.parents_version = Parents Version | |||||
| modelarts.train_job.run_parameter=Run Parameter | modelarts.train_job.run_parameter=Run Parameter | ||||
| modelarts.train_job.add_run_parameter=Add Run Parameter | modelarts.train_job.add_run_parameter=Add Run Parameter | ||||
| modelarts.train_job.parameter_name=Parameter Name | modelarts.train_job.parameter_name=Parameter Name | ||||
| @@ -816,9 +816,11 @@ total_count_get_error=查询总页数失败。 | |||||
| last_update_time_error=查询最新更新时间失败。 | last_update_time_error=查询最新更新时间失败。 | ||||
| get_repo_stat_error=查询当前仓库的统计信息失败。 | get_repo_stat_error=查询当前仓库的统计信息失败。 | ||||
| get_repo_info_error=查询当前仓库信息失败。 | get_repo_info_error=查询当前仓库信息失败。 | ||||
| generate_statistic_file_error=生成文件失败。 | |||||
| repo_stat_inspect=项目分析 | |||||
| all=所有 | |||||
| modelarts.status=状态 | |||||
| modelarts.createtime=创建时间 | |||||
| modelarts.version_nums=版本数 | |||||
| modelarts.computing_resources=计算资源 | |||||
| modelarts.notebook=调试任务 | modelarts.notebook=调试任务 | ||||
| modelarts.train_job=训练任务 | modelarts.train_job=训练任务 | ||||
| modelarts.train_job.new_debug=新建调试任务 | modelarts.train_job.new_debug=新建调试任务 | ||||
| @@ -826,6 +828,10 @@ modelarts.train_job.new_train=新建训练任务 | |||||
| modelarts.train_job.config=配置信息 | modelarts.train_job.config=配置信息 | ||||
| modelarts.train_job.new=新建训练任务 | modelarts.train_job.new=新建训练任务 | ||||
| modelarts.train_job.new_place=描述字数不超过256个字符 | modelarts.train_job.new_place=描述字数不超过256个字符 | ||||
| modelarts.modify=修改 | |||||
| modelarts.current_version=当前版本 | |||||
| modelarts.parent_version=父版本 | |||||
| modelarts.run_version=运行版本 | |||||
| @@ -845,9 +851,14 @@ modelarts.train_job.frames=常用框架 | |||||
| modelarts.train_job.algorithm_origin=算法来源 | modelarts.train_job.algorithm_origin=算法来源 | ||||
| modelarts.train_job.AI_driver=AI引擎 | modelarts.train_job.AI_driver=AI引擎 | ||||
| modelarts.train_job.start_file=启动文件 | modelarts.train_job.start_file=启动文件 | ||||
| modelarts.train_job.boot_file_helper=启动文件是您程序执行的入口文件,必须是以.py结尾的文件。 | |||||
| modelarts.train_job.boot_file_helper=启动文件是您程序执行的入口文件,必须是以.py结尾的文件。比如train.py、main.py、example/train.py、case/main.py。 | |||||
| modelarts.train_job.boot_file_place=填写启动文件路径,默认为train.py | modelarts.train_job.boot_file_place=填写启动文件路径,默认为train.py | ||||
| modelarts.train_job.dataset=数据集 | modelarts.train_job.dataset=数据集 | ||||
| modelarts.code_version=代码分支 | |||||
| modelarts.parents_version=基于版本 | |||||
| modelarts.train_job.compute_node=计算节点 | |||||
| modelarts.train_job.train_dataset=训练数据集 | |||||
| modelarts.train_job.run_parameter=运行参数 | modelarts.train_job.run_parameter=运行参数 | ||||
| modelarts.train_job.add_run_parameter=增加运行参数 | modelarts.train_job.add_run_parameter=增加运行参数 | ||||
| modelarts.train_job.parameter_name=参数名 | modelarts.train_job.parameter_name=参数名 | ||||
| @@ -874,8 +874,12 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
| }) | }) | ||||
| m.Group("/train-job", func() { | m.Group("/train-job", func() { | ||||
| m.Group("/:jobid", func() { | m.Group("/:jobid", func() { | ||||
| m.Get("", repo.GetModelArtsTrainJob) | |||||
| m.Get("", repo.GetModelArtsTrainJobVersion) | |||||
| m.Get("/log", repo.TrainJobGetLog) | m.Get("/log", repo.TrainJobGetLog) | ||||
| m.Post("/del_version", repo.DelTrainJobVersion) | |||||
| m.Post("/stop_version", repo.StopTrainJobVersion) | |||||
| m.Get("/model_list", repo.ModelList) | |||||
| m.Get("/model_download", repo.ModelDownload) | |||||
| }) | }) | ||||
| }) | }) | ||||
| }, reqRepoReader(models.UnitTypeCloudBrain)) | }, reqRepoReader(models.UnitTypeCloudBrain)) | ||||
| @@ -6,12 +6,15 @@ | |||||
| package repo | package repo | ||||
| import ( | import ( | ||||
| "net/http" | |||||
| "strconv" | |||||
| "strings" | |||||
| "code.gitea.io/gitea/models" | "code.gitea.io/gitea/models" | ||||
| "code.gitea.io/gitea/modules/context" | "code.gitea.io/gitea/modules/context" | ||||
| "code.gitea.io/gitea/modules/log" | "code.gitea.io/gitea/modules/log" | ||||
| "code.gitea.io/gitea/modules/modelarts" | "code.gitea.io/gitea/modules/modelarts" | ||||
| "net/http" | |||||
| "strconv" | |||||
| "code.gitea.io/gitea/modules/storage" | |||||
| ) | ) | ||||
| func GetModelArtsNotebook(ctx *context.APIContext) { | func GetModelArtsNotebook(ctx *context.APIContext) { | ||||
| @@ -72,56 +75,274 @@ func GetModelArtsTrainJob(ctx *context.APIContext) { | |||||
| } | } | ||||
| ctx.JSON(http.StatusOK, map[string]interface{}{ | ctx.JSON(http.StatusOK, map[string]interface{}{ | ||||
| "JobID": jobID, | |||||
| "JobStatus": job.Status, | |||||
| "JobDuration": job.Duration, | |||||
| "JobID": jobID, | |||||
| "JobStatus": job.Status, | |||||
| "JobDuration": job.Duration, | |||||
| }) | }) | ||||
| } | } | ||||
| func TrainJobGetLog(ctx *context.APIContext) { | |||||
| func GetModelArtsTrainJobVersion(ctx *context.APIContext) { | |||||
| var ( | var ( | ||||
| err error | err error | ||||
| ) | ) | ||||
| log.Info("test") | |||||
| jobID := ctx.Params(":jobid") | |||||
| versionName := ctx.Query("version_name") | |||||
| job, err := models.GetCloudbrainByJobIDAndVersionName(jobID, versionName) | |||||
| if err != nil { | |||||
| ctx.NotFound(err) | |||||
| return | |||||
| } | |||||
| result, err := modelarts.GetTrainJob(jobID, strconv.FormatInt(job.VersionID, 10)) | |||||
| if err != nil { | |||||
| ctx.NotFound(err) | |||||
| return | |||||
| } | |||||
| job.Status = modelarts.TransTrainJobStatus(result.IntStatus) | |||||
| job.Duration = result.Duration | |||||
| job.TrainJobDuration = result.TrainJobDuration | |||||
| if result.Duration != 0 { | |||||
| job.TrainJobDuration = addZero(result.Duration/3600000) + ":" + addZero(result.Duration%3600000/60000) + ":" + addZero(result.Duration%60000/1000) | |||||
| } else { | |||||
| job.TrainJobDuration = "00:00:00" | |||||
| } | |||||
| err = models.UpdateTrainJobVersion(job) | |||||
| if err != nil { | |||||
| log.Error("UpdateJob failed:", err) | |||||
| } | |||||
| ctx.JSON(http.StatusOK, map[string]interface{}{ | |||||
| "JobID": jobID, | |||||
| "JobStatus": job.Status, | |||||
| "JobDuration": job.TrainJobDuration, | |||||
| }) | |||||
| } | |||||
| func addZero(t int64) (m string) { | |||||
| if t < 10 { | |||||
| m = "0" + strconv.FormatInt(t, 10) | |||||
| return m | |||||
| } else { | |||||
| return strconv.FormatInt(t, 10) | |||||
| } | |||||
| } | |||||
| func TrainJobGetLog(ctx *context.APIContext) { | |||||
| var ( | |||||
| err error | |||||
| ) | |||||
| var jobID = ctx.Params(":jobid") | var jobID = ctx.Params(":jobid") | ||||
| var logFileName = ctx.Query("file_name") | |||||
| var versionName = ctx.Query("version_name") | |||||
| // var logFileName = ctx.Query("file_name") | |||||
| var baseLine = ctx.Query("base_line") | var baseLine = ctx.Query("base_line") | ||||
| var order = ctx.Query("order") | var order = ctx.Query("order") | ||||
| var lines = ctx.Query("lines") | |||||
| lines_int, err := strconv.Atoi(lines) | |||||
| if err != nil { | |||||
| log.Error("change lines(%d) string to int failed", lines_int) | |||||
| } | |||||
| if order != modelarts.OrderDesc && order != modelarts.OrderAsc { | if order != modelarts.OrderDesc && order != modelarts.OrderAsc { | ||||
| log.Error("order(%s) check failed", order) | log.Error("order(%s) check failed", order) | ||||
| ctx.JSON(http.StatusBadRequest, map[string]interface{}{ | ctx.JSON(http.StatusBadRequest, map[string]interface{}{ | ||||
| "err_msg": "order check failed", | |||||
| "err_msg": "order check failed", | |||||
| }) | }) | ||||
| return | return | ||||
| } | } | ||||
| task, err := models.GetCloudbrainByJobID(jobID) | |||||
| resultLogFile, result, err := trainJobGetLogContent(jobID, versionName, baseLine, order, lines_int) | |||||
| if err != nil { | if err != nil { | ||||
| log.Error("GetCloudbrainByJobID(%s) failed:%v", jobID, err.Error()) | |||||
| ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ | |||||
| "err_msg": "GetCloudbrainByJobID failed", | |||||
| }) | |||||
| log.Error("trainJobGetLog(%s) failed:%v", jobID, err.Error()) | |||||
| // ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobShow, nil) | |||||
| return | return | ||||
| } | } | ||||
| result, err := modelarts.GetTrainJobLog(jobID, strconv.FormatInt(task.VersionID, 10), baseLine, logFileName, order, modelarts.Lines) | |||||
| ctx.Data["log_file_name"] = resultLogFile.LogFileList[0] | |||||
| ctx.JSON(http.StatusOK, map[string]interface{}{ | |||||
| "JobID": jobID, | |||||
| "LogFileName": resultLogFile.LogFileList[0], | |||||
| "StartLine": result.StartLine, | |||||
| "EndLine": result.EndLine, | |||||
| "Content": result.Content, | |||||
| "Lines": result.Lines, | |||||
| }) | |||||
| } | |||||
| func trainJobGetLogContent(jobID string, versionName string, baseLine string, order string, lines int) (*models.GetTrainJobLogFileNamesResult, *models.GetTrainJobLogResult, error) { | |||||
| task, err := models.GetCloudbrainByJobIDAndVersionName(jobID, versionName) | |||||
| if err != nil { | |||||
| log.Error("GetCloudbrainByJobID(%s) failed:%v", jobID, err.Error()) | |||||
| return nil, nil, err | |||||
| } | |||||
| resultLogFile, err := modelarts.GetTrainJobLogFileNames(jobID, strconv.FormatInt(task.VersionID, 10)) | |||||
| if err != nil { | |||||
| log.Error("GetTrainJobLogFileNames(%s) failed:%v", jobID, err.Error()) | |||||
| return nil, nil, err | |||||
| } | |||||
| result, err := modelarts.GetTrainJobLog(jobID, strconv.FormatInt(task.VersionID, 10), baseLine, resultLogFile.LogFileList[0], order, lines) | |||||
| if err != nil { | if err != nil { | ||||
| log.Error("GetTrainJobLog(%s) failed:%v", jobID, err.Error()) | log.Error("GetTrainJobLog(%s) failed:%v", jobID, err.Error()) | ||||
| ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ | |||||
| "err_msg": "GetTrainJobLog failed", | |||||
| }) | |||||
| return nil, nil, err | |||||
| } | |||||
| return resultLogFile, result, err | |||||
| } | |||||
| func DelTrainJobVersion(ctx *context.APIContext) { | |||||
| var ( | |||||
| err error | |||||
| ) | |||||
| var jobID = ctx.Params(":jobid") | |||||
| var versionName = ctx.Query("version_name") | |||||
| task, err := models.GetCloudbrainByJobIDAndVersionName(jobID, versionName) | |||||
| if err != nil { | |||||
| log.Error("GetCloudbrainByJobID(%s) failed:%v", task.JobName, err.Error()) | |||||
| ctx.NotFound(err) | |||||
| return | return | ||||
| } | } | ||||
| //删除modelarts上的记录 | |||||
| _, err = modelarts.DelTrainJobVersion(jobID, strconv.FormatInt(task.VersionID, 10)) | |||||
| if err != nil { | |||||
| log.Error("DelTrainJobVersion(%s) failed:%v", task.JobName, err.Error()) | |||||
| ctx.NotFound(err) | |||||
| return | |||||
| } | |||||
| //删除数据库记录 | |||||
| err = models.DeleteJob(task) | |||||
| if err != nil { | |||||
| ctx.ServerError("DeleteJob failed", err) | |||||
| ctx.NotFound(err) | |||||
| return | |||||
| } | |||||
| //获取删除后的版本数量 | |||||
| repo := ctx.Repo.Repository | |||||
| VersionTaskList, VersionListCount, err := models.CloudbrainsVersionList(&models.CloudbrainsOptions{ | |||||
| RepoID: repo.ID, | |||||
| Type: models.TypeCloudBrainTwo, | |||||
| JobType: string(models.JobTypeTrain), | |||||
| JobID: jobID, | |||||
| }) | |||||
| if err != nil { | |||||
| ctx.ServerError("get VersionListCount faild", err) | |||||
| return | |||||
| } | |||||
| // 判断当前删掉的任务是否是最新版本,若是,将排序后的TotalVersionCount置为删掉的最新版本的TotalVersionCount,若不是,按时间排序后的版本列表的第一个版本设置为最新版本,TotalVersionCount不变 | |||||
| if task.IsLatestVersion == modelarts.IsLatestVersion { | |||||
| err = models.SetVersionCountAndLatestVersion(jobID, VersionTaskList[0].Cloudbrain.VersionName, VersionListCount, modelarts.IsLatestVersion, task.TotalVersionCount) | |||||
| if err != nil { | |||||
| ctx.ServerError("UpdateJobVersionCount failed", err) | |||||
| return | |||||
| } | |||||
| } else { | |||||
| err = models.SetVersionCountAndLatestVersion(jobID, VersionTaskList[0].VersionName, VersionListCount, modelarts.IsLatestVersion, VersionTaskList[0].Cloudbrain.TotalVersionCount) | |||||
| if err != nil { | |||||
| ctx.ServerError("UpdateJobVersionCount failed", err) | |||||
| return | |||||
| } | |||||
| } | |||||
| ctx.JSON(http.StatusOK, map[string]interface{}{ | ctx.JSON(http.StatusOK, map[string]interface{}{ | ||||
| "JobID": jobID, | |||||
| "StartLine": result.StartLine, | |||||
| "EndLine": result.EndLine, | |||||
| "Content": result.Content, | |||||
| "Lines": result.Lines, | |||||
| "JobID": jobID, | |||||
| "VersionName": versionName, | |||||
| "StatusOK": 0, | |||||
| }) | }) | ||||
| } | } | ||||
| func StopTrainJobVersion(ctx *context.APIContext) { | |||||
| var ( | |||||
| err error | |||||
| ) | |||||
| var jobID = ctx.Params(":jobid") | |||||
| var versionName = ctx.Query("version_name") | |||||
| task, err := models.GetCloudbrainByJobIDAndVersionName(jobID, versionName) | |||||
| if err != nil { | |||||
| log.Error("GetCloudbrainByJobID(%s) failed:%v", task.JobName, err.Error()) | |||||
| return | |||||
| } | |||||
| _, err = modelarts.StopTrainJob(jobID, strconv.FormatInt(task.VersionID, 10)) | |||||
| if err != nil { | |||||
| log.Error("StopTrainJob(%s) failed:%v", task.JobName, err.Error()) | |||||
| return | |||||
| } | |||||
| ctx.JSON(http.StatusOK, map[string]interface{}{ | |||||
| "JobID": jobID, | |||||
| "VersionName": versionName, | |||||
| "StatusOK": 0, | |||||
| }) | |||||
| } | |||||
| func ModelList(ctx *context.APIContext) { | |||||
| var ( | |||||
| err error | |||||
| ) | |||||
| var jobID = ctx.Params(":jobid") | |||||
| var versionName = ctx.Query("version_name") | |||||
| parentDir := ctx.Query("parentDir") | |||||
| dirArray := strings.Split(parentDir, "/") | |||||
| task, err := models.GetCloudbrainByJobIDAndVersionName(jobID, versionName) | |||||
| if err != nil { | |||||
| log.Error("GetCloudbrainByJobID(%s) failed:%v", task.JobName, err.Error()) | |||||
| return | |||||
| } | |||||
| VersionOutputPath := modelarts.GetVersionOutputPathByTotalVersionCount(task.TotalVersionCount) | |||||
| parentDir = VersionOutputPath + "/" + parentDir | |||||
| models, err := storage.GetObsListObject(task.JobName, parentDir) | |||||
| if err != nil { | |||||
| log.Info("get TrainJobListModel failed:", err) | |||||
| ctx.ServerError("GetObsListObject:", err) | |||||
| return | |||||
| } | |||||
| ctx.JSON(http.StatusOK, map[string]interface{}{ | |||||
| "JobID": jobID, | |||||
| "VersionName": versionName, | |||||
| "StatusOK": 0, | |||||
| "Path": dirArray, | |||||
| "Dirs": models, | |||||
| "task": task, | |||||
| "PageIsCloudBrain": true, | |||||
| }) | |||||
| } | |||||
| func ModelDownload(ctx *context.APIContext) { | |||||
| var ( | |||||
| err error | |||||
| ) | |||||
| var jobID = ctx.Params(":jobid") | |||||
| versionName := ctx.Query("version_name") | |||||
| parentDir := ctx.Query("parent_dir") | |||||
| fileName := ctx.Query("file_name") | |||||
| task, err := models.GetCloudbrainByJobIDAndVersionName(jobID, versionName) | |||||
| if err != nil { | |||||
| log.Error("GetCloudbrainByJobID(%s) failed:%v", task.JobName, err.Error()) | |||||
| return | |||||
| } | |||||
| VersionOutputPath := modelarts.GetVersionOutputPathByTotalVersionCount(task.TotalVersionCount) | |||||
| parentDir = VersionOutputPath + "/" + parentDir | |||||
| url, err := storage.GetObsCreateSignedUrl(task.JobName, parentDir, fileName) | |||||
| if err != nil { | |||||
| log.Error("GetObsCreateSignedUrl failed: %v", err.Error(), ctx.Data["msgID"]) | |||||
| ctx.ServerError("GetObsCreateSignedUrl", err) | |||||
| return | |||||
| } | |||||
| http.Redirect(ctx.Resp, ctx.Req.Request, url, http.StatusMovedPermanently) | |||||
| } | |||||
| @@ -34,7 +34,7 @@ const ( | |||||
| tplModelArtsTrainJobIndex base.TplName = "repo/modelarts/trainjob/index" | tplModelArtsTrainJobIndex base.TplName = "repo/modelarts/trainjob/index" | ||||
| tplModelArtsTrainJobNew base.TplName = "repo/modelarts/trainjob/new" | tplModelArtsTrainJobNew base.TplName = "repo/modelarts/trainjob/new" | ||||
| tplModelArtsTrainJobShow base.TplName = "repo/modelarts/trainjob/show" | tplModelArtsTrainJobShow base.TplName = "repo/modelarts/trainjob/show" | ||||
| tplModelArtsTrainJobShowModels base.TplName = "repo/modelarts/trainjob/models/index" | |||||
| tplModelArtsTrainJobVersionNew base.TplName = "repo/modelarts/trainjob/version_new" | |||||
| ) | ) | ||||
| // MustEnableDataset check if repository enable internal cb | // MustEnableDataset check if repository enable internal cb | ||||
| @@ -58,8 +58,8 @@ func NotebookIndex(ctx *context.Context) { | |||||
| Page: page, | Page: page, | ||||
| PageSize: setting.UI.IssuePagingNum, | PageSize: setting.UI.IssuePagingNum, | ||||
| }, | }, | ||||
| RepoID: repo.ID, | |||||
| Type: models.TypeCloudBrainTwo, | |||||
| RepoID: repo.ID, | |||||
| Type: models.TypeCloudBrainTwo, | |||||
| JobType: string(models.JobTypeDebug), | JobType: string(models.JobTypeDebug), | ||||
| }) | }) | ||||
| if err != nil { | if err != nil { | ||||
| @@ -266,14 +266,6 @@ func NotebookDel(ctx *context.Context) { | |||||
| func TrainJobIndex(ctx *context.Context) { | func TrainJobIndex(ctx *context.Context) { | ||||
| MustEnableModelArts(ctx) | MustEnableModelArts(ctx) | ||||
| //can, err := canUserCreateTrainJob(ctx.User.ID) | |||||
| //if err != nil { | |||||
| // ctx.ServerError("canUserCreateTrainJob", err) | |||||
| // return | |||||
| //} | |||||
| // | |||||
| //ctx.Data["CanCreate"] = can | |||||
| repo := ctx.Repo.Repository | repo := ctx.Repo.Repository | ||||
| page := ctx.QueryInt("page") | page := ctx.QueryInt("page") | ||||
| if page <= 0 { | if page <= 0 { | ||||
| @@ -285,9 +277,10 @@ func TrainJobIndex(ctx *context.Context) { | |||||
| Page: page, | Page: page, | ||||
| PageSize: setting.UI.IssuePagingNum, | PageSize: setting.UI.IssuePagingNum, | ||||
| }, | }, | ||||
| RepoID: repo.ID, | |||||
| Type: models.TypeCloudBrainTwo, | |||||
| JobType: string(models.JobTypeTrain), | |||||
| RepoID: repo.ID, | |||||
| Type: models.TypeCloudBrainTwo, | |||||
| JobType: string(models.JobTypeTrain), | |||||
| IsLatestVersion: modelarts.IsLatestVersion, | |||||
| }) | }) | ||||
| if err != nil { | if err != nil { | ||||
| ctx.ServerError("Cloudbrain", err) | ctx.ServerError("Cloudbrain", err) | ||||
| @@ -369,12 +362,116 @@ func trainJobNewDataPrepare(ctx *context.Context) error { | |||||
| outputObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.OutputPath | outputObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.OutputPath | ||||
| ctx.Data["train_url"] = outputObsPath | ctx.Data["train_url"] = outputObsPath | ||||
| Branches, err := ctx.Repo.GitRepo.GetBranches() | |||||
| if err != nil { | |||||
| ctx.ServerError("GetBranches error:", err) | |||||
| return err | |||||
| } | |||||
| ctx.Data["Branches"] = Branches | |||||
| ctx.Data["BranchesCount"] = len(Branches) | |||||
| 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 | |||||
| return nil | |||||
| } | |||||
| func TrainJobNewVersion(ctx *context.Context) { | |||||
| err := trainJobNewVersionDataPrepare(ctx) | |||||
| if err != nil { | |||||
| ctx.ServerError("get new train-job info failed", err) | |||||
| return | |||||
| } | |||||
| ctx.HTML(200, tplModelArtsTrainJobVersionNew) | |||||
| } | |||||
| func trainJobNewVersionDataPrepare(ctx *context.Context) 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 | |||||
| } | |||||
| t := time.Now() | |||||
| var jobName = cutString(ctx.User.Name, 5) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:] | |||||
| ctx.Data["job_name"] = task.JobName | |||||
| attachs, err := models.GetModelArtsUserAttachments(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 | |||||
| var flavorInfos modelarts.Flavor | |||||
| if err = json.Unmarshal([]byte(setting.TrainJobFLAVORINFOS), &flavorInfos); err != nil { | |||||
| ctx.ServerError("json.Unmarshal failed:", err) | |||||
| return err | |||||
| } | |||||
| ctx.Data["flavor_infos"] = flavorInfos.Info | |||||
| 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 | |||||
| outputObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.OutputPath | |||||
| ctx.Data["train_url"] = outputObsPath | |||||
| Branches, err := ctx.Repo.GitRepo.GetBranches() | |||||
| if err != nil { | |||||
| ctx.ServerError("GetBranches error:", err) | |||||
| return err | |||||
| } | |||||
| ctx.Data["branches"] = Branches | |||||
| ctx.Data["branch_name"] = task.BranchName | |||||
| ctx.Data["description"] = task.Description | |||||
| ctx.Data["boot_file"] = task.BootFile | |||||
| ctx.Data["dataset_name"] = task.DatasetName | |||||
| ctx.Data["work_server_number"] = task.WorkServerNumber | |||||
| ctx.Data["flavor_name"] = task.FlavorName | |||||
| ctx.Data["engine_name"] = task.EngineName | |||||
| ctx.Data["uuid"] = task.Uuid | |||||
| ctx.Data["flavor_code"] = task.FlavorCode | |||||
| ctx.Data["engine_id"] = task.EngineID | |||||
| 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 | ctx.Data["config_list"] = configList.ParaConfigs | ||||
| return nil | return nil | ||||
| @@ -382,6 +479,7 @@ func trainJobNewDataPrepare(ctx *context.Context) error { | |||||
| func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) { | func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) { | ||||
| ctx.Data["PageIsTrainJob"] = true | ctx.Data["PageIsTrainJob"] = true | ||||
| VersionOutputPath := modelarts.GetVersionOutputPathByTotalVersionCount(modelarts.TotalVersionCount) | |||||
| jobName := form.JobName | jobName := form.JobName | ||||
| uuid := form.Attachment | uuid := form.Attachment | ||||
| description := form.Description | description := form.Description | ||||
| @@ -395,23 +493,15 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||||
| repo := ctx.Repo.Repository | repo := ctx.Repo.Repository | ||||
| codeLocalPath := setting.JobPath + jobName + modelarts.CodePath | codeLocalPath := setting.JobPath + jobName + modelarts.CodePath | ||||
| codeObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.CodePath | codeObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.CodePath | ||||
| outputObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.OutputPath | |||||
| logObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.LogPath | |||||
| outputObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.OutputPath + VersionOutputPath + "/" | |||||
| logObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.LogPath + VersionOutputPath + "/" | |||||
| dataPath := "/" + setting.Bucket + "/" + setting.BasePath + path.Join(uuid[0:1], uuid[1:2]) + "/" + uuid + uuid + "/" | dataPath := "/" + setting.Bucket + "/" + setting.BasePath + path.Join(uuid[0:1], uuid[1:2]) + "/" + uuid + uuid + "/" | ||||
| branch_name := form.BranchName | |||||
| isLatestVersion := modelarts.IsLatestVersion | |||||
| FlavorName := form.FlavorName | |||||
| VersionCount := modelarts.VersionCount | |||||
| EngineName := form.EngineName | |||||
| //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.RenderWithErr("the user can not create train-job", tplModelArtsTrainJobNew, &form) | |||||
| // return | |||||
| //} | |||||
| //param check | |||||
| if err := paramCheckCreateTrainJob(form); err != nil { | if err := paramCheckCreateTrainJob(form); err != nil { | ||||
| log.Error("paramCheckCreateTrainJob failed:(%v)", err) | log.Error("paramCheckCreateTrainJob failed:(%v)", err) | ||||
| trainJobNewDataPrepare(ctx) | trainJobNewDataPrepare(ctx) | ||||
| @@ -430,30 +520,35 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||||
| if err == nil { | if err == nil { | ||||
| os.RemoveAll(codeLocalPath) | os.RemoveAll(codeLocalPath) | ||||
| } | } | ||||
| if err := git.Clone(repo.RepoPath(), codeLocalPath, git.CloneRepoOptions{}); err != nil { | |||||
| log.Error("创建任务失败,任务名称已存在!: %s (%v)", repo.FullName(), err) | |||||
| gitRepo, _ := git.OpenRepository(repo.RepoPath()) | |||||
| commitID, _ := gitRepo.GetBranchCommitID(branch_name) | |||||
| if err := git.Clone(repo.RepoPath(), codeLocalPath, git.CloneRepoOptions{ | |||||
| Branch: branch_name, | |||||
| }); err != nil { | |||||
| log.Error("创建任务失败,服务器超时!: %s (%v)", repo.FullName(), err) | |||||
| trainJobNewDataPrepare(ctx) | trainJobNewDataPrepare(ctx) | ||||
| ctx.Data["bootFile"] = form.BootFile | ctx.Data["bootFile"] = form.BootFile | ||||
| ctx.Data["uuid"] = form.Attachment | ctx.Data["uuid"] = form.Attachment | ||||
| ctx.Data["datasetName"] = attach.Name | ctx.Data["datasetName"] = attach.Name | ||||
| ctx.Data["params"] = form.Params | ctx.Data["params"] = form.Params | ||||
| ctx.Data["branch_name"] = branch_name | |||||
| trainJobNewDataPrepare(ctx) | trainJobNewDataPrepare(ctx) | ||||
| // ctx.RenderWithErr("Failed to clone repository", tplModelArtsTrainJobNew, &form) | |||||
| ctx.RenderWithErr("创建任务失败,任务名称已存在!", tplModelArtsTrainJobNew, &form) | |||||
| // ctx.RenderWithErr(err, tplModelArtsTrainJobNew, &form) | |||||
| ctx.RenderWithErr("创建任务失败,服务器超时!", tplModelArtsTrainJobNew, &form) | |||||
| return | return | ||||
| } | } | ||||
| //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); 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) | ||||
| trainJobNewDataPrepare(ctx) | 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); 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) | ||||
| trainJobNewDataPrepare(ctx) | trainJobNewDataPrepare(ctx) | ||||
| ctx.RenderWithErr("Failed to obsMkdir_log", tplModelArtsTrainJobNew, &form) | ctx.RenderWithErr("Failed to obsMkdir_log", tplModelArtsTrainJobNew, &form) | ||||
| @@ -532,19 +627,28 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||||
| } | } | ||||
| req := &modelarts.GenerateTrainJobReq{ | req := &modelarts.GenerateTrainJobReq{ | ||||
| JobName: jobName, | |||||
| DataUrl: dataPath, | |||||
| Description: description, | |||||
| CodeObsPath: codeObsPath, | |||||
| BootFile: codeObsPath + bootFile, | |||||
| TrainUrl: outputObsPath, | |||||
| FlavorCode: flavorCode, | |||||
| WorkServerNumber: workServerNumber, | |||||
| EngineID: int64(engineID), | |||||
| LogUrl: logObsPath, | |||||
| PoolID: poolID, | |||||
| Uuid: uuid, | |||||
| Parameters: param, | |||||
| JobName: jobName, | |||||
| DataUrl: dataPath, | |||||
| Description: description, | |||||
| CodeObsPath: codeObsPath, | |||||
| BootFileUrl: codeObsPath + bootFile, | |||||
| BootFile: bootFile, | |||||
| TrainUrl: outputObsPath, | |||||
| FlavorCode: flavorCode, | |||||
| WorkServerNumber: workServerNumber, | |||||
| EngineID: int64(engineID), | |||||
| LogUrl: logObsPath, | |||||
| PoolID: poolID, | |||||
| Uuid: uuid, | |||||
| Parameters: parameters.Parameter, | |||||
| CommitID: commitID, | |||||
| IsLatestVersion: isLatestVersion, | |||||
| BranchName: branch_name, | |||||
| Params: form.Params, | |||||
| FlavorName: FlavorName, | |||||
| EngineName: EngineName, | |||||
| VersionCount: VersionCount, | |||||
| TotalVersionCount: modelarts.TotalVersionCount, | |||||
| } | } | ||||
| err = modelarts.GenerateTrainJob(ctx, req) | err = modelarts.GenerateTrainJob(ctx, req) | ||||
| @@ -555,12 +659,221 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||||
| ctx.Data["uuid"] = form.Attachment | ctx.Data["uuid"] = form.Attachment | ||||
| ctx.Data["datasetName"] = attach.Name | ctx.Data["datasetName"] = attach.Name | ||||
| ctx.Data["params"] = form.Params | ctx.Data["params"] = form.Params | ||||
| ctx.Data["branch_name"] = branch_name | |||||
| ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobNew, &form) | ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/train-job") | ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/train-job") | ||||
| } | } | ||||
| func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) { | |||||
| ctx.Data["PageIsTrainJob"] = true | |||||
| var jobID = ctx.Params(":jobid") | |||||
| latestTask, err := models.GetCloudbrainByJobIDAndIsLatestVersion(jobID, modelarts.IsLatestVersion) | |||||
| if err != nil { | |||||
| ctx.ServerError("GetCloudbrainByJobIDAndIsLatestVersion faild:", err) | |||||
| return | |||||
| } | |||||
| VersionOutputPath := modelarts.GetVersionOutputPathByTotalVersionCount(latestTask.TotalVersionCount + 1) | |||||
| jobName := form.JobName | |||||
| uuid := form.Attachment | |||||
| description := form.Description | |||||
| workServerNumber := form.WorkServerNumber | |||||
| engineID := form.EngineID | |||||
| bootFile := form.BootFile | |||||
| flavorCode := form.Flavor | |||||
| params := form.Params | |||||
| poolID := form.PoolID | |||||
| isSaveParam := form.IsSaveParam | |||||
| repo := ctx.Repo.Repository | |||||
| codeLocalPath := setting.JobPath + jobName + modelarts.CodePath | |||||
| codeObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.CodePath | |||||
| outputObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.OutputPath + VersionOutputPath + "/" | |||||
| logObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.LogPath + VersionOutputPath + "/" | |||||
| dataPath := "/" + setting.Bucket + "/" + setting.BasePath + path.Join(uuid[0:1], uuid[1:2]) + "/" + uuid + uuid + "/" | |||||
| branch_name := form.BranchName | |||||
| PreVersionName := form.VersionName | |||||
| FlavorName := form.FlavorName | |||||
| EngineName := form.EngineName | |||||
| isLatestVersion := modelarts.IsLatestVersion | |||||
| if err := paramCheckCreateTrainJob(form); err != nil { | |||||
| log.Error("paramCheckCreateTrainJob failed:(%v)", err) | |||||
| trainJobNewVersionDataPrepare(ctx) | |||||
| ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobVersionNew, &form) | |||||
| return | |||||
| } | |||||
| attach, err := models.GetAttachmentByUUID(uuid) | |||||
| if err != nil { | |||||
| log.Error("GetAttachmentByUUID(%s) failed:%v", uuid, err.Error()) | |||||
| return | |||||
| } | |||||
| //todo: del the codeLocalPath | |||||
| _, err = ioutil.ReadDir(codeLocalPath) | |||||
| if err == nil { | |||||
| os.RemoveAll(codeLocalPath) | |||||
| } | |||||
| gitRepo, _ := git.OpenRepository(repo.RepoPath()) | |||||
| commitID, _ := gitRepo.GetBranchCommitID(branch_name) | |||||
| if err := git.Clone(repo.RepoPath(), codeLocalPath, git.CloneRepoOptions{ | |||||
| Branch: branch_name, | |||||
| }); err != nil { | |||||
| log.Error("创建任务失败,任务名称已存在!: %s (%v)", repo.FullName(), err) | |||||
| trainJobNewVersionDataPrepare(ctx) | |||||
| ctx.Data["bootFile"] = form.BootFile | |||||
| ctx.Data["uuid"] = form.Attachment | |||||
| ctx.Data["datasetName"] = attach.Name | |||||
| ctx.Data["params"] = form.Params | |||||
| ctx.Data["branch_name"] = branch_name | |||||
| ctx.RenderWithErr("创建任务失败,任务名称已存在!", tplModelArtsTrainJobVersionNew, &form) | |||||
| return | |||||
| } | |||||
| //todo: upload code (send to file_server todo this work?) | |||||
| if err := obsMkdir(setting.CodePathPrefix + jobName + modelarts.OutputPath + VersionOutputPath + "/"); err != nil { | |||||
| log.Error("Failed to obsMkdir_output: %s (%v)", repo.FullName(), err) | |||||
| trainJobNewVersionDataPrepare(ctx) | |||||
| ctx.RenderWithErr("Failed to obsMkdir_output", tplModelArtsTrainJobVersionNew, &form) | |||||
| return | |||||
| } | |||||
| if err := obsMkdir(setting.CodePathPrefix + jobName + modelarts.LogPath + VersionOutputPath + "/"); err != nil { | |||||
| log.Error("Failed to obsMkdir_log: %s (%v)", repo.FullName(), err) | |||||
| trainJobNewVersionDataPrepare(ctx) | |||||
| ctx.RenderWithErr("Failed to obsMkdir_log", tplModelArtsTrainJobVersionNew, &form) | |||||
| return | |||||
| } | |||||
| if err := uploadCodeToObs(codeLocalPath, jobName, ""); err != nil { | |||||
| log.Error("Failed to uploadCodeToObs: %s (%v)", repo.FullName(), err) | |||||
| trainJobNewVersionDataPrepare(ctx) | |||||
| ctx.RenderWithErr("Failed to uploadCodeToObs", tplModelArtsTrainJobVersionNew, &form) | |||||
| return | |||||
| } | |||||
| //todo: del local code? | |||||
| var parameters models.Parameters | |||||
| param := make([]models.Parameter, 0) | |||||
| param = append(param, models.Parameter{ | |||||
| Label: modelarts.TrainUrl, | |||||
| Value: outputObsPath, | |||||
| }, models.Parameter{ | |||||
| Label: modelarts.DataUrl, | |||||
| Value: dataPath, | |||||
| }) | |||||
| if len(params) != 0 { | |||||
| err := json.Unmarshal([]byte(params), ¶meters) | |||||
| if err != nil { | |||||
| log.Error("Failed to Unmarshal params: %s (%v)", params, err) | |||||
| trainJobNewVersionDataPrepare(ctx) | |||||
| ctx.RenderWithErr("运行参数错误", tplModelArtsTrainJobVersionNew, &form) | |||||
| return | |||||
| } | |||||
| for _, parameter := range parameters.Parameter { | |||||
| if parameter.Label != modelarts.TrainUrl && parameter.Label != modelarts.DataUrl { | |||||
| param = append(param, models.Parameter{ | |||||
| Label: parameter.Label, | |||||
| Value: parameter.Value, | |||||
| }) | |||||
| } | |||||
| } | |||||
| } | |||||
| //save param config | |||||
| if isSaveParam == "on" { | |||||
| if form.ParameterTemplateName == "" { | |||||
| log.Error("ParameterTemplateName is empty") | |||||
| trainJobNewVersionDataPrepare(ctx) | |||||
| 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: parameters.Parameter, | |||||
| }) | |||||
| if err != nil { | |||||
| log.Error("Failed to CreateTrainJobConfig: %v", err) | |||||
| trainJobNewVersionDataPrepare(ctx) | |||||
| ctx.RenderWithErr("保存作业参数失败:"+err.Error(), tplModelArtsTrainJobVersionNew, &form) | |||||
| return | |||||
| } | |||||
| } | |||||
| if err != nil { | |||||
| log.Error("getFlavorNameByEngineID(%s) failed:%v", engineID, err.Error()) | |||||
| ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobVersionNew, &form) | |||||
| return | |||||
| } | |||||
| task, err := models.GetCloudbrainByJobIDAndVersionName(jobID, PreVersionName) | |||||
| if err != nil { | |||||
| log.Error("GetCloudbrainByJobIDAndVersionName(%s) failed:%v", jobID, err.Error()) | |||||
| ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobVersionNew, &form) | |||||
| return | |||||
| } | |||||
| req := &modelarts.GenerateTrainJobReq{ | |||||
| JobName: task.JobName, | |||||
| DataUrl: dataPath, | |||||
| Description: description, | |||||
| CodeObsPath: codeObsPath, | |||||
| BootFileUrl: codeObsPath + bootFile, | |||||
| BootFile: bootFile, | |||||
| TrainUrl: outputObsPath, | |||||
| FlavorCode: flavorCode, | |||||
| WorkServerNumber: workServerNumber, | |||||
| IsLatestVersion: isLatestVersion, | |||||
| EngineID: int64(engineID), | |||||
| LogUrl: logObsPath, | |||||
| PoolID: poolID, | |||||
| Uuid: uuid, | |||||
| Params: form.Params, | |||||
| Parameters: parameters.Parameter, | |||||
| PreVersionId: task.VersionID, | |||||
| CommitID: commitID, | |||||
| BranchName: branch_name, | |||||
| FlavorName: FlavorName, | |||||
| EngineName: EngineName, | |||||
| PreVersionName: PreVersionName, | |||||
| TotalVersionCount: latestTask.TotalVersionCount + 1, | |||||
| } | |||||
| err = modelarts.GenerateTrainJobVersion(ctx, req, jobID) | |||||
| if err != nil { | |||||
| log.Error("GenerateTrainJob failed:%v", err.Error()) | |||||
| trainJobNewVersionDataPrepare(ctx) | |||||
| ctx.Data["bootFile"] = form.BootFile | |||||
| ctx.Data["uuid"] = form.Attachment | |||||
| ctx.Data["datasetName"] = attach.Name | |||||
| ctx.Data["params"] = form.Params | |||||
| ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobVersionNew, &form) | |||||
| return | |||||
| } | |||||
| ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/train-job") | |||||
| // ctx.HTML(http.StatusOK, tplModelArtsTrainJobShow) | |||||
| } | |||||
| // readDir reads the directory named by dirname and returns | // readDir reads the directory named by dirname and returns | ||||
| // a list of directory entries sorted by filename. | // a list of directory entries sorted by filename. | ||||
| func readDir(dirname string) ([]os.FileInfo, error) { | func readDir(dirname string) ([]os.FileInfo, error) { | ||||
| @@ -652,69 +965,59 @@ func TrainJobShow(ctx *context.Context) { | |||||
| ctx.Data["PageIsCloudBrain"] = true | ctx.Data["PageIsCloudBrain"] = true | ||||
| var jobID = ctx.Params(":jobid") | var jobID = ctx.Params(":jobid") | ||||
| task, err := models.GetCloudbrainByJobID(jobID) | |||||
| if err != nil { | |||||
| log.Error("GetCloudbrainByJobID(%s) failed:%v", jobID, err.Error()) | |||||
| ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobShow, nil) | |||||
| return | |||||
| } | |||||
| // attach, err := models.GetAttachmentByUUID(task.Uuid) | |||||
| // if err != nil { | |||||
| // log.Error("GetAttachmentByUUID(%s) failed:%v", jobID, err.Error()) | |||||
| // ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobShow, nil) | |||||
| // return | |||||
| // } | |||||
| repo := ctx.Repo.Repository | |||||
| page := ctx.QueryInt("page") | |||||
| if page <= 0 { | |||||
| page = 1 | |||||
| } | |||||
| VersionListTasks, VersionListCount, err := models.CloudbrainsVersionList(&models.CloudbrainsOptions{ | |||||
| ListOptions: models.ListOptions{ | |||||
| Page: page, | |||||
| PageSize: setting.UI.IssuePagingNum, | |||||
| }, | |||||
| RepoID: repo.ID, | |||||
| Type: models.TypeCloudBrainTwo, | |||||
| JobType: string(models.JobTypeTrain), | |||||
| JobID: jobID, | |||||
| }) | |||||
| result, err := modelarts.GetTrainJob(jobID, strconv.FormatInt(task.VersionID, 10)) | |||||
| if err != nil { | if err != nil { | ||||
| log.Error("GetJob(%s) failed:%v", jobID, err.Error()) | |||||
| log.Error("GetVersionListTasks(%s) failed:%v", jobID, err.Error()) | |||||
| ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobShow, nil) | ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobShow, nil) | ||||
| return | return | ||||
| } | } | ||||
| //将运行参数转化为epoch_size = 3, device_target = Ascend的格式 | |||||
| for i, _ := range VersionListTasks { | |||||
| if result != nil { | |||||
| result.CreateTime = time.Unix(int64(result.LongCreateTime/1000), 0).Format("2006-01-02 15:04:05") | |||||
| if result.Duration != 0 { | |||||
| result.TrainJobDuration = addZero(result.Duration/3600000) + ":" + addZero(result.Duration%3600000/60000) + ":" + addZero(result.Duration%60000/1000) | |||||
| var parameters models.Parameters | |||||
| } else { | |||||
| result.TrainJobDuration = "00:00:00" | |||||
| } | |||||
| result.Status = modelarts.TransTrainJobStatus(result.IntStatus) | |||||
| err = models.SetTrainJobStatusByJobID(jobID, result.Status, result.Duration, string(result.TrainJobDuration)) | |||||
| err := json.Unmarshal([]byte(VersionListTasks[i].Parameters), ¶meters) | |||||
| if err != nil { | if err != nil { | ||||
| ctx.ServerError("UpdateJob failed", err) | |||||
| log.Error("Failed to Unmarshal Parameters: %s (%v)", VersionListTasks[i].Parameters, err) | |||||
| trainJobNewDataPrepare(ctx) | |||||
| return | return | ||||
| } | } | ||||
| result.DatasetName = task.DatasetName | |||||
| } | |||||
| resultLogFile, resultLog, err := trainJobGetLog(jobID) | |||||
| if err != nil { | |||||
| log.Error("trainJobGetLog(%s) failed:%v", jobID, err.Error()) | |||||
| ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobShow, nil) | |||||
| return | |||||
| if len(parameters.Parameter) > 0 { | |||||
| paramTemp := "" | |||||
| for _, Parameter := range parameters.Parameter { | |||||
| param := Parameter.Label + " = " + Parameter.Value + ", " | |||||
| paramTemp = paramTemp + param | |||||
| } | |||||
| VersionListTasks[i].Parameters = paramTemp[:len(paramTemp)-2] | |||||
| } else { | |||||
| VersionListTasks[i].Parameters = "" | |||||
| } | |||||
| } | } | ||||
| ctx.Data["log_file_name"] = resultLogFile.LogFileList[0] | |||||
| ctx.Data["log"] = resultLog | |||||
| ctx.Data["task"] = task | |||||
| ctx.Data["jobID"] = jobID | ctx.Data["jobID"] = jobID | ||||
| ctx.Data["result"] = result | |||||
| ctx.Data["jobName"] = VersionListTasks[0].JobName | |||||
| ctx.Data["version_list_task"] = VersionListTasks | |||||
| ctx.Data["version_list_count"] = VersionListCount | |||||
| ctx.HTML(http.StatusOK, tplModelArtsTrainJobShow) | ctx.HTML(http.StatusOK, tplModelArtsTrainJobShow) | ||||
| } | } | ||||
| func addZero(t int64) (m string) { | |||||
| if t < 10 { | |||||
| m = "0" + strconv.FormatInt(t, 10) | |||||
| return m | |||||
| } else { | |||||
| return strconv.FormatInt(t, 10) | |||||
| } | |||||
| } | |||||
| func TrainJobGetLog(ctx *context.Context) { | func TrainJobGetLog(ctx *context.Context) { | ||||
| ctx.Data["PageIsTrainJob"] = true | ctx.Data["PageIsTrainJob"] = true | ||||
| @@ -771,24 +1074,34 @@ func trainJobGetLog(jobID string) (*models.GetTrainJobLogFileNamesResult, *model | |||||
| func TrainJobDel(ctx *context.Context) { | func TrainJobDel(ctx *context.Context) { | ||||
| var jobID = ctx.Params(":jobid") | var jobID = ctx.Params(":jobid") | ||||
| task, err := models.GetCloudbrainByJobID(jobID) | |||||
| repo := ctx.Repo.Repository | |||||
| VersionListTasks, _, err := models.CloudbrainsVersionList(&models.CloudbrainsOptions{ | |||||
| RepoID: repo.ID, | |||||
| Type: models.TypeCloudBrainTwo, | |||||
| JobType: string(models.JobTypeTrain), | |||||
| JobID: jobID, | |||||
| }) | |||||
| if err != nil { | if err != nil { | ||||
| log.Error("GetCloudbrainByJobID(%s) failed:%v", task.JobName, err.Error()) | |||||
| ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobIndex, nil) | |||||
| ctx.ServerError("get VersionListTasks failed", err) | |||||
| return | return | ||||
| } | } | ||||
| //删除modelarts上的任务记录 | |||||
| _, err = modelarts.DelTrainJob(jobID) | _, err = modelarts.DelTrainJob(jobID) | ||||
| if err != nil { | if err != nil { | ||||
| log.Error("DelTrainJob(%s) failed:%v", task.JobName, err.Error()) | |||||
| log.Error("DelTrainJob(%s) failed:%v", jobID, err.Error()) | |||||
| ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobIndex, nil) | ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobIndex, nil) | ||||
| return | return | ||||
| } | } | ||||
| err = models.DeleteJob(task) | |||||
| if err != nil { | |||||
| ctx.ServerError("DeleteJob failed", err) | |||||
| return | |||||
| //删除数据库Cloudbrain表的记录 | |||||
| for _, task := range VersionListTasks { | |||||
| err = models.DeleteJob(&task.Cloudbrain) | |||||
| if err != nil { | |||||
| ctx.ServerError("DeleteJob failed", err) | |||||
| return | |||||
| } | |||||
| } | } | ||||
| ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/train-job") | ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/train-job") | ||||
| @@ -876,43 +1189,3 @@ func getConfigList(perPage, page int, sortBy, order, searchContent, configType s | |||||
| return list, nil | return list, nil | ||||
| } | } | ||||
| func TrainJobShowModels(ctx *context.Context) { | |||||
| ctx.Data["PageIsCloudBrain"] = true | |||||
| jobID := ctx.Params(":jobid") | |||||
| parentDir := ctx.Query("parentDir") | |||||
| dirArray := strings.Split(parentDir, "/") | |||||
| task, err := models.GetCloudbrainByJobID(jobID) | |||||
| if err != nil { | |||||
| log.Error("no such job!", ctx.Data["msgID"]) | |||||
| ctx.ServerError("no such job:", err) | |||||
| return | |||||
| } | |||||
| models, err := storage.GetObsListObject(task.JobName, parentDir) | |||||
| if err != nil { | |||||
| log.Info("get TrainJobListModel failed:", err) | |||||
| ctx.ServerError("GetObsListObject:", err) | |||||
| return | |||||
| } | |||||
| ctx.Data["Path"] = dirArray | |||||
| ctx.Data["Dirs"] = models | |||||
| ctx.Data["task"] = task | |||||
| ctx.Data["JobID"] = jobID | |||||
| ctx.HTML(200, tplModelArtsTrainJobShowModels) | |||||
| } | |||||
| func TrainJobDownloadModel(ctx *context.Context) { | |||||
| parentDir := ctx.Query("parentDir") | |||||
| fileName := ctx.Query("fileName") | |||||
| jobName := ctx.Query("jobName") | |||||
| url, err := storage.GetObsCreateSignedUrl(jobName, parentDir, fileName) | |||||
| if err != nil { | |||||
| log.Error("GetObsCreateSignedUrl failed: %v", err.Error(), ctx.Data["msgID"]) | |||||
| ctx.ServerError("GetObsCreateSignedUrl", err) | |||||
| return | |||||
| } | |||||
| http.Redirect(ctx.Resp, ctx.Req.Request, url, http.StatusMovedPermanently) | |||||
| } | |||||
| @@ -971,16 +971,6 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
| }, context.RepoRef()) | }, context.RepoRef()) | ||||
| m.Group("/modelarts", func() { | m.Group("/modelarts", func() { | ||||
| // m.Get("", reqRepoCloudBrainReader, repo.ModelArtsIndex) | |||||
| // m.Group("/:jobid", func() { | |||||
| // m.Get("", reqRepoCloudBrainReader, repo.ModelArtsShow) | |||||
| // m.Get("/debug", reqRepoCloudBrainReader, repo.ModelArtsDebug) | |||||
| // m.Post("/stop", reqRepoCloudBrainWriter, repo.ModelArtsStop) | |||||
| // m.Post("/del", reqRepoCloudBrainWriter, repo.ModelArtsDel) | |||||
| // }) | |||||
| // m.Get("/create", reqRepoCloudBrainWriter, repo.ModelArtsNew) | |||||
| // m.Post("/create", reqRepoCloudBrainWriter, bindIgnErr(auth.CreateModelArtsForm{}), repo.ModelArtsCreate) | |||||
| m.Group("/notebook", func() { | m.Group("/notebook", func() { | ||||
| m.Get("", reqRepoCloudBrainReader, repo.NotebookIndex) | m.Get("", reqRepoCloudBrainReader, repo.NotebookIndex) | ||||
| m.Group("/:jobid", func() { | m.Group("/:jobid", func() { | ||||
| @@ -999,12 +989,12 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
| m.Get("", reqRepoCloudBrainReader, repo.TrainJobShow) | m.Get("", reqRepoCloudBrainReader, repo.TrainJobShow) | ||||
| m.Post("/stop", reqRepoCloudBrainWriter, repo.TrainJobStop) | m.Post("/stop", reqRepoCloudBrainWriter, repo.TrainJobStop) | ||||
| m.Post("/del", reqRepoCloudBrainWriter, repo.TrainJobDel) | m.Post("/del", reqRepoCloudBrainWriter, repo.TrainJobDel) | ||||
| m.Get("/log", reqRepoCloudBrainReader, repo.TrainJobGetLog) | |||||
| m.Get("/models", reqRepoCloudBrainReader, repo.TrainJobShowModels) | |||||
| m.Get("/download_model", reqRepoCloudBrainReader, repo.TrainJobDownloadModel) | |||||
| m.Get("/create_version", reqRepoCloudBrainReader, repo.TrainJobNewVersion) | |||||
| m.Post("/create_version", reqRepoCloudBrainWriter, bindIgnErr(auth.CreateModelArtsTrainJobForm{}), repo.TrainJobCreateVersion) | |||||
| }) | }) | ||||
| m.Get("/create", reqRepoCloudBrainReader, repo.TrainJobNew) | m.Get("/create", reqRepoCloudBrainReader, repo.TrainJobNew) | ||||
| m.Post("/create", reqRepoCloudBrainWriter, bindIgnErr(auth.CreateModelArtsTrainJobForm{}), repo.TrainJobCreate) | m.Post("/create", reqRepoCloudBrainWriter, bindIgnErr(auth.CreateModelArtsTrainJobForm{}), repo.TrainJobCreate) | ||||
| m.Get("/para-config-list", reqRepoCloudBrainReader, repo.TrainJobGetConfigList) | m.Get("/para-config-list", reqRepoCloudBrainReader, repo.TrainJobGetConfigList) | ||||
| }) | }) | ||||
| }, context.RepoRef()) | }, context.RepoRef()) | ||||
| @@ -239,8 +239,8 @@ | |||||
| <div class="column"> | <div class="column"> | ||||
| <div class="ui blue small menu compact selectcloudbrain"> | <div class="ui blue small menu compact selectcloudbrain"> | ||||
| <a class="active item">{{$.i18n.Tr "repo.modelarts.notebook"}}</a> | |||||
| <!-- <a class="item" href="{{.RepoLink}}/modelarts">训练任务</a> --> | |||||
| <a class="active item" href="{{.RepoLink}}/cloudbrain">{{$.i18n.Tr "repo.modelarts.notebook"}}</a> | |||||
| <a class="item" href="{{.RepoLink}}/modelarts/train-job">{{$.i18n.Tr "repo.modelarts.train_job"}}</a> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div class="column right aligned"> | <div class="column right aligned"> | ||||
| @@ -6,7 +6,19 @@ | |||||
| {{template "base/alert" .}} | {{template "base/alert" .}} | ||||
| <h4 class="ui header" id="vertical-segment"> | <h4 class="ui header" id="vertical-segment"> | ||||
| <a href="javascript:window.history.back();"><i class="arrow left icon"></i>返回</a> | |||||
| <div class="ui breadcrumb"> | |||||
| <a class="section" href="{{.RepoLink}}/cloudbrain"> | |||||
| {{.i18n.Tr "repo.cloudbrain"}} | |||||
| </a> | |||||
| <div class="divider"> / </div> | |||||
| <a class="section" href="{{.RepoLink}}/modelarts/notebook"> | |||||
| {{$.i18n.Tr "repo.modelarts.notebook"}} | |||||
| </a> | |||||
| <div class="divider"> / </div> | |||||
| {{with .task}} | |||||
| <div class="active section">{{.JobName}}</div> | |||||
| {{end}} | |||||
| </div> | |||||
| </h4> | </h4> | ||||
| <div> | <div> | ||||
| <div class="ui yellow segment"> | <div class="ui yellow segment"> | ||||
| @@ -6,7 +6,19 @@ | |||||
| {{template "base/alert" .}} | {{template "base/alert" .}} | ||||
| <h4 class="ui header" id="vertical-segment"> | <h4 class="ui header" id="vertical-segment"> | ||||
| <a href="javascript:window.history.back();"><i class="arrow left icon"></i>返回</a> | |||||
| <div class="ui breadcrumb"> | |||||
| <a class="section" href="{{.RepoLink}}/cloudbrain"> | |||||
| {{.i18n.Tr "repo.cloudbrain"}} | |||||
| </a> | |||||
| <div class="divider"> / </div> | |||||
| <a class="section" href="{{.RepoLink}}/cloudbrain"> | |||||
| {{$.i18n.Tr "repo.modelarts.notebook"}} | |||||
| </a> | |||||
| <div class="divider"> / </div> | |||||
| {{with .task}} | |||||
| <div class="active section">{{.JobName}}</div> | |||||
| {{end}} | |||||
| </div> | |||||
| </h4> | </h4> | ||||
| <div> | <div> | ||||
| <div class="ui yellow segment"> | <div class="ui yellow segment"> | ||||
| @@ -180,6 +180,12 @@ | |||||
| cursor: pointer; | cursor: pointer; | ||||
| pointer-events: none; | pointer-events: none; | ||||
| } | } | ||||
| .fontsize14{ | |||||
| font-size: 14px; | |||||
| } | |||||
| .padding0{ | |||||
| padding: 0 !important; | |||||
| } | |||||
| </style> | </style> | ||||
| <!-- 弹窗 --> | <!-- 弹窗 --> | ||||
| @@ -232,13 +238,13 @@ | |||||
| <div class="column"> | <div class="column"> | ||||
| <div class="ui blue small menu compact selectcloudbrain"> | <div class="ui blue small menu compact selectcloudbrain"> | ||||
| <a class="item" href="{{.RepoLink}}/modelarts/notebook">{{$.i18n.Tr "repo.modelarts.notebook"}}</a> | |||||
| <a class="item" href="{{.RepoLink}}/cloudbrain">{{$.i18n.Tr "repo.modelarts.notebook"}}</a> | |||||
| <a class="active item" href="{{.RepoLink}}/modelarts/train-job">{{$.i18n.Tr "repo.modelarts.train_job"}}</a> | <a class="active item" href="{{.RepoLink}}/modelarts/train-job">{{$.i18n.Tr "repo.modelarts.train_job"}}</a> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div class="column right aligned"> | <div class="column right aligned"> | ||||
| <div class="ui selection dropdown" style="min-width: 10em;min-height:2.6em;border-radius: .28571429rem;margin-right: 1em;padding: .67em 3.2em .7em 1em;"> | |||||
| <!-- <div class="ui selection dropdown" style="min-width: 10em;min-height:2.6em;border-radius: .28571429rem;margin-right: 1em;padding: .67em 3.2em .7em 1em;"> | |||||
| {{svg "octicon-server" 16}} | {{svg "octicon-server" 16}} | ||||
| <div class="default text" style="color: rgba(0,0,0,.87);"> Ascend NPU</div> | <div class="default text" style="color: rgba(0,0,0,.87);"> Ascend NPU</div> | ||||
| <i class="dropdown icon"></i> | <i class="dropdown icon"></i> | ||||
| @@ -246,7 +252,7 @@ | |||||
| <a class="item" href="{{.RepoLink}}/cloudbrain" data-value="11">CPU / GPU</a> | <a class="item" href="{{.RepoLink}}/cloudbrain" data-value="11">CPU / GPU</a> | ||||
| <a class="item" href="{{.RepoLink}}/modelarts/notebook" data-value="22">Ascend NPU</a> | <a class="item" href="{{.RepoLink}}/modelarts/notebook" data-value="22">Ascend NPU</a> | ||||
| </div> | </div> | ||||
| </div> | |||||
| </div> --> | |||||
| {{if .Permission.CanWrite $.UnitTypeCloudBrain}} | {{if .Permission.CanWrite $.UnitTypeCloudBrain}} | ||||
| <a class="ui green button" href="{{.RepoLink}}/modelarts/train-job/create">{{$.i18n.Tr "repo.modelarts.train_job.new_train"}}</a>{{end}} | <a class="ui green button" href="{{.RepoLink}}/modelarts/train-job/create">{{$.i18n.Tr "repo.modelarts.train_job.new_train"}}</a>{{end}} | ||||
| </div> | </div> | ||||
| @@ -278,20 +284,29 @@ | |||||
| <!-- 表头 --> | <!-- 表头 --> | ||||
| <div class="ui grid stackable" style="background: #f0f0f0;;"> | <div class="ui grid stackable" style="background: #f0f0f0;;"> | ||||
| <div class="row"> | <div class="row"> | ||||
| <div class="five wide column"> | |||||
| <div class="three wide column padding0"> | |||||
| <span style="margin:0 6px">{{$.i18n.Tr "repo.cloudbrain_task"}}</span> | <span style="margin:0 6px">{{$.i18n.Tr "repo.cloudbrain_task"}}</span> | ||||
| </div> | </div> | ||||
| <div class="three wide column"> | |||||
| <span>{{$.i18n.Tr "repo.cloudbrain_status_createtime"}}</span> | |||||
| <div class="one wide column text center padding0"> | |||||
| <span style="margin:0 6px">{{$.i18n.Tr "repo.modelarts.version_nums"}}</span> | |||||
| </div> | </div> | ||||
| <div class="two wide column"> | |||||
| <div class="two wide column text center padding0"> | |||||
| <span>{{$.i18n.Tr "repo.modelarts.status"}}</span> | |||||
| </div> | |||||
| <div class="two wide column text center padding0"> | |||||
| <span>{{$.i18n.Tr "repo.modelarts.createtime"}}</span> | |||||
| </div> | |||||
| <div class="two wide column text center padding0"> | |||||
| <span>{{$.i18n.Tr "repo.cloudbrain_status_runtime"}}</span> | <span>{{$.i18n.Tr "repo.cloudbrain_status_runtime"}}</span> | ||||
| </div> | </div> | ||||
| <div class="one wide column text center"> | |||||
| <div class="two wide column text center padding0"> | |||||
| <span>{{$.i18n.Tr "repo.modelarts.computing_resources"}}</span> | |||||
| </div> | |||||
| <div class="one wide column text center padding0"> | |||||
| <span>{{$.i18n.Tr "repo.cloudbrain_creator"}}</span> | <span>{{$.i18n.Tr "repo.cloudbrain_creator"}}</span> | ||||
| </div> | </div> | ||||
| <div class="five wide column text center"> | |||||
| <span style="margin-left: 6rem;">{{$.i18n.Tr "repo.cloudbrain_operate"}}</span> | |||||
| <div class="three wide column text center padding0"> | |||||
| <span>{{$.i18n.Tr "repo.cloudbrain_operate"}}</span> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| @@ -305,38 +320,44 @@ | |||||
| <div class="row"> | <div class="row"> | ||||
| <!-- 任务名 --> | <!-- 任务名 --> | ||||
| <div class="five wide column"> | |||||
| <a class="title" href="{{$.Link}}/{{.JobID}}" title="{{.JobName}}" style="font-size: 15px;"> | |||||
| <div class="three wide column padding0"> | |||||
| <a class="title" href="{{$.Link}}/{{.JobID}}" title="{{.JobName}}" style="font-size: 12px;"> | |||||
| <span class="fitted" style="vertical-align: middle;">{{svg "octicon-tasklist" 16}}</span> | <span class="fitted" style="vertical-align: middle;">{{svg "octicon-tasklist" 16}}</span> | ||||
| <span class="fitted" style="width: 90%;vertical-align: middle;margin-left: 0.4rem;">{{.JobName}}</span> | <span class="fitted" style="width: 90%;vertical-align: middle;margin-left: 0.4rem;">{{.JobName}}</span> | ||||
| </a> | </a> | ||||
| </div> | </div> | ||||
| <div class="three wide column"> | |||||
| <!--任务状态 --> | |||||
| <!-- <span class="ui compact button job-status" id="{{.JobID}}" data-repopath="{{$.RepoRelPath}}" data-jobid="{{.JobID}}"> | |||||
| {{.Status}} | |||||
| </span> --> | |||||
| <!-- 版本数量 --> | |||||
| <div class="one wide column text center padding0"> | |||||
| <span>{{.VersionCount}} </span> | |||||
| </div> | |||||
| <!-- 任务状态 --> | |||||
| <div class="two wide column padding0" style="padding-left: 2.2rem !important;"> | |||||
| <span class="job-status" id="{{.JobID}}" data-repopath="{{$.RepoRelPath}}" data-jobid="{{.JobID}}" data-version="{{.VersionName}}"> | |||||
| <span><i id="{{.JobID}}-icon" style="vertical-align: middle;" class="{{.Status}}"></i><span id="{{.JobID}}-text" style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span> | |||||
| </span> | |||||
| </div> | |||||
| <!-- 任务创建时间 --> | |||||
| <div class="two wide column text center padding0"> | |||||
| <span style="font-size: 12px;" class="">{{TimeSinceUnix .Cloudbrain.CreatedUnix $.Lang}}</span> | |||||
| </div> | |||||
| <!-- <div class="two wide column"> | |||||
| <span class="job-status" id="{{.JobID}}" data-repopath="{{$.RepoRelPath}}" data-jobid="{{.JobID}}"> | <span class="job-status" id="{{.JobID}}" data-repopath="{{$.RepoRelPath}}" data-jobid="{{.JobID}}"> | ||||
| <span><i id="{{.JobID}}-icon" style="vertical-align: middle;" class="{{.Status}}"></i><span id="{{.JobID}}-text" style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span> | <span><i id="{{.JobID}}-icon" style="vertical-align: middle;" class="{{.Status}}"></i><span id="{{.JobID}}-text" style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span> | ||||
| </span> | </span> | ||||
| <!-- 任务创建时间 --> | |||||
| <span style="font-size: 12px;margin-left: 0.4rem;" class="">{{TimeSinceUnix .Cloudbrain.CreatedUnix $.Lang}}</span> | <span style="font-size: 12px;margin-left: 0.4rem;" class="">{{TimeSinceUnix .Cloudbrain.CreatedUnix $.Lang}}</span> | ||||
| </div> --> | |||||
| <!-- 任务运行时间 --> | |||||
| <div class="two wide column text center padding0"> | |||||
| <span style="font-size: 12px;" id="duration-{{.JobID}}"></span> | |||||
| </div> | </div> | ||||
| <div class="two wide column"> | |||||
| <!--任务状态 --> | |||||
| <!-- <span class="ui compact button job-status" id="{{.JobID}}" data-repopath="{{$.RepoRelPath}}" data-jobid="{{.JobID}}"> | |||||
| {{.Status}} | |||||
| </span> --> | |||||
| <span id="duration-{{.JobID}}"></span> | |||||
| <!-- 任务创建时间 --> | |||||
| <!-- <span style="font-size: 12px;margin-left: 0.4rem;" class="">{{TimeSinceUnix .Cloudbrain.CreatedUnix $.Lang}}</span> --> | |||||
| <!-- 计算资源 --> | |||||
| <div class="two wide column text center padding0"> | |||||
| <span style="font-size: 12px;">{{.ComputeResource}}</span> | |||||
| </div> | </div> | ||||
| <div class="one wide column text center"> | |||||
| <!-- 创建者 --> | |||||
| <div class="one wide column text center padding0"> | |||||
| {{if .User.Name}} | {{if .User.Name}} | ||||
| <a href="{{AppSubUrl}}/{{.User.Name}}" title="{{.User.Name}}"><img class="ui avatar image" src="{{.User.RelAvatarLink}}"></a> | <a href="{{AppSubUrl}}/{{.User.Name}}" title="{{.User.Name}}"><img class="ui avatar image" src="{{.User.RelAvatarLink}}"></a> | ||||
| {{else}} | {{else}} | ||||
| @@ -344,56 +365,41 @@ | |||||
| {{end}} | {{end}} | ||||
| </div> | </div> | ||||
| <div class="five wide column text right"> | |||||
| <div class="three wide column text center padding0"> | |||||
| <div class="ui compact buttons"> | <div class="ui compact buttons"> | ||||
| <!-- <a class="ui basic blue button" href="{{$.Link}}/{{.JobID}}"> | |||||
| 查看 | |||||
| </a> | |||||
| <a class="ui basic {{if not .CanDebug}}disabled {{else}}blue {{end}}button" href="{{$.Link}}/{{.JobID}}/debug" target="_blank"> | |||||
| 调试 | |||||
| </a> --> | |||||
| <form id="stopForm-{{.JobID}}" action="{{$.Link}}/{{.JobID}}/stop" method="post" style="margin-left:-1px;"> | |||||
| <form id="stopForm-{{.JobID}}" action="{{$.Link}}/{{.JobID}}/stop" method="post"> | |||||
| {{$.CsrfTokenHtml}} | {{$.CsrfTokenHtml}} | ||||
| {{if $.Permission.CanWrite $.UnitTypeCloudBrain}} | {{if $.Permission.CanWrite $.UnitTypeCloudBrain}} | ||||
| <a id="stop-model-debug-{{.JobID}}" class="ui basic {{if eq .Status "KILLED" "FAILED" "START_FAILED" "KILLING" "COMPLETED"}}disabled {{else}}blue {{end}}button" onclick="document.getElementById('stopForm-{{.JobID}}').submit();"> | |||||
| <a style="padding: 0.5rem 1rem;" id="stop-model-debug-{{.JobID}}" class="ui basic {{if eq .Status "KILLED" "FAILED" "START_FAILED" "KILLING" "COMPLETED"}}disabled {{else}}blue {{end}}button" onclick="document.getElementById('stopForm-{{.JobID}}').submit();"> | |||||
| {{$.i18n.Tr "repo.stop"}} | {{$.i18n.Tr "repo.stop"}} | ||||
| </a> | </a> | ||||
| {{else}} | {{else}} | ||||
| <a class="ui basic disabled button" onclick="document.getElementById('stopForm-{{.JobID}}').submit();"> | |||||
| <a style="padding: 0.5rem 1rem;" class="ui basic disabled button" onclick="document.getElementById('stopForm-{{.JobID}}').submit();"> | |||||
| {{$.i18n.Tr "repo.stop"}} | {{$.i18n.Tr "repo.stop"}} | ||||
| </a> | </a> | ||||
| {{end}} | {{end}} | ||||
| </form> | </form> | ||||
| </div> | </div> | ||||
| <div class="ui compact buttons" style="margin-right:10px;"> | |||||
| <!-- 模型下载 --> | |||||
| <a class="ui basic blue button" href="{{$.Link}}/{{.JobID}}/models" target="_blank"> | |||||
| <!-- 模型下载 --> | |||||
| <!-- <div class="ui compact buttons"> | |||||
| <a style="padding: 0.5rem;" class="ui basic blue button" href="{{$.Link}}/{{.JobID}}/models" target="_blank"> | |||||
| {{$.i18n.Tr "repo.model_download"}} | {{$.i18n.Tr "repo.model_download"}} | ||||
| </a> | </a> | ||||
| <!-- 接收结果 --> | |||||
| <!-- <iframe src="" frameborder="0" name="iframeContent" style="display: none;"></iframe> | |||||
| <a class="imageBtn ui basic {{if not .CanDebug}}disabled {{else}}blue {{end}}button" value="{{.CanDebug}}">提交镜像</a> --> | |||||
| </div> | |||||
| </div> --> | |||||
| <!-- 删除任务 --> | <!-- 删除任务 --> | ||||
| <form class="ui compact buttons" id="delForm-{{.JobID}}" action="{{$.Link}}/{{.JobID}}/del" method="post"> | <form class="ui compact buttons" id="delForm-{{.JobID}}" action="{{$.Link}}/{{.JobID}}/del" method="post"> | ||||
| {{$.CsrfTokenHtml}} | {{$.CsrfTokenHtml}} | ||||
| {{if $.Permission.CanWrite $.UnitTypeCloudBrain}} | {{if $.Permission.CanWrite $.UnitTypeCloudBrain}} | ||||
| <a id="model-delete-{{.JobID}}" class="ui compact {{if or (eq .Status "RUNNING") (eq .Status "INIT") (eq .Status "CREATING") (eq .Status "WAITING") }}disabled {{else}}red {{end}}button" onclick="assertDelete(this)" style="border-radius: .28571429rem;"> | |||||
| <a style="padding: 0.5rem 1rem;margin-left:0.2rem" id="model-delete-{{.JobID}}" class="ui compact {{if or (eq .Status "RUNNING") (eq .Status "INIT") (eq .Status "CREATING") (eq .Status "WAITING") }}disabled {{else}}red {{end}}button" onclick="assertDelete(this)" style="border-radius: .28571429rem;"> | |||||
| {{$.i18n.Tr "repo.delete"}} | {{$.i18n.Tr "repo.delete"}} | ||||
| </a> | </a> | ||||
| {{else}} | {{else}} | ||||
| <a class="ui compact disabled button" onclick="assertDelete(this)" style="border-radius: .28571429rem;"> | |||||
| <a style="padding: 0.5rem 1rem;margin-left:0.2rem" class="ui compact disabled button" onclick="assertDelete(this)" style="border-radius: .28571429rem;"> | |||||
| {{$.i18n.Tr "repo.delete"}} | {{$.i18n.Tr "repo.delete"}} | ||||
| </a> | </a> | ||||
| {{end}} | {{end}} | ||||
| </form> | </form> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| {{end}} {{template "base/paginate" .}} | {{end}} {{template "base/paginate" .}} | ||||
| @@ -435,6 +441,8 @@ | |||||
| {{template "base/footer" .}} | {{template "base/footer" .}} | ||||
| <script> | <script> | ||||
| console.log({{.Tasks}}) | |||||
| // 调试和评分新开窗口 | // 调试和评分新开窗口 | ||||
| function stop(obj) { | function stop(obj) { | ||||
| if (obj.style.color != "rgb(204, 204, 204)") { | if (obj.style.color != "rgb(204, 204, 204)") { | ||||
| @@ -484,11 +492,12 @@ | |||||
| $(".job-status").each((index, job) => { | $(".job-status").each((index, job) => { | ||||
| const jobID = job.dataset.jobid; | const jobID = job.dataset.jobid; | ||||
| const repoPath = job.dataset.repopath; | const repoPath = job.dataset.repopath; | ||||
| $.get(`/api/v1/repos/${repoPath}/modelarts/train-job/${jobID}`, (data) => { | |||||
| const versionname = job.dataset.version | |||||
| $.get(`/api/v1/repos/${repoPath}/modelarts/train-job/${jobID}?version_name=${versionname}`, (data) => { | |||||
| console.log(data) | |||||
| const duration = data.JobDuration | const duration = data.JobDuration | ||||
| const jobID = data.JobID | const jobID = data.JobID | ||||
| let train_duration = runtime(duration) | |||||
| $('#duration-'+jobID).text(train_duration) | |||||
| $('#duration-'+jobID).text(duration) | |||||
| }) | }) | ||||
| }) | }) | ||||
| @@ -501,17 +510,18 @@ | |||||
| $(".job-status").each((index, job) => { | $(".job-status").each((index, job) => { | ||||
| const jobID = job.dataset.jobid; | const jobID = job.dataset.jobid; | ||||
| const repoPath = job.dataset.repopath; | const repoPath = job.dataset.repopath; | ||||
| const versionname = job.dataset.version | |||||
| if (job.textContent.trim() == 'IMAGE_FAILED' || job.textContent.trim() == 'SUBMIT_FAILED' || job.textContent.trim() == 'DELETE_FAILED' | if (job.textContent.trim() == 'IMAGE_FAILED' || job.textContent.trim() == 'SUBMIT_FAILED' || job.textContent.trim() == 'DELETE_FAILED' | ||||
| || job.textContent.trim() == 'KILLED' || job.textContent.trim() == 'COMPLETED' || job.textContent.trim() == 'FAILED' | || job.textContent.trim() == 'KILLED' || job.textContent.trim() == 'COMPLETED' || job.textContent.trim() == 'FAILED' | ||||
| || job.textContent.trim() == 'CANCELED' || job.textContent.trim() == 'LOST') { | || job.textContent.trim() == 'CANCELED' || job.textContent.trim() == 'LOST') { | ||||
| return | return | ||||
| } | } | ||||
| $.get(`/api/v1/repos/${repoPath}/modelarts/train-job/${jobID}`, (data) => { | |||||
| $.get(`/api/v1/repos/${repoPath}/modelarts/train-job/${jobID}?version_name=${versionname}`, (data) => { | |||||
| const jobID = data.JobID | const jobID = data.JobID | ||||
| const status = data.JobStatus | const status = data.JobStatus | ||||
| const duration = data.JobDuration | const duration = data.JobDuration | ||||
| $('#duration-'+jobID).text(duration) | |||||
| if (status != job.textContent.trim()) { | if (status != job.textContent.trim()) { | ||||
| $('#' + jobID+'-icon').removeClass().addClass(status) | $('#' + jobID+'-icon').removeClass().addClass(status) | ||||
| $('#' + jobID+ '-text').text(status) | $('#' + jobID+ '-text').text(status) | ||||
| @@ -520,8 +530,7 @@ | |||||
| if(status==="RUNNING"){ | if(status==="RUNNING"){ | ||||
| $('#model-debug-'+jobID).removeClass('disabled') | $('#model-debug-'+jobID).removeClass('disabled') | ||||
| $('#model-debug-'+jobID).addClass('blue') | $('#model-debug-'+jobID).addClass('blue') | ||||
| let train_duration = runtime(duration) | |||||
| $('#duration-'+jobID).text(train_duration) | |||||
| // $('#duration-'+jobID).text(duration) | |||||
| } | } | ||||
| if(status!=="RUNNING"){ | if(status!=="RUNNING"){ | ||||
| @@ -535,7 +544,7 @@ | |||||
| $('#model-delete-'+jobID).removeClass('red') | $('#model-delete-'+jobID).removeClass('red') | ||||
| $('#model-delete-'+jobID).addClass('disabled') | $('#model-delete-'+jobID).addClass('disabled') | ||||
| } | } | ||||
| if(status=="KILLED" || status=="FAILED" || status=="KILLING"){ | |||||
| if(status=="KILLED" || status=="FAILED" || status=="KILLING" || status=="COMPLETED"){ | |||||
| $('#stop-model-debug-'+jobID).removeClass('blue') | $('#stop-model-debug-'+jobID).removeClass('blue') | ||||
| $('#stop-model-debug-'+jobID).addClass('disabled') | $('#stop-model-debug-'+jobID).addClass('disabled') | ||||
| $('#model-delete-'+jobID).removeClass('disabled') | $('#model-delete-'+jobID).removeClass('disabled') | ||||
| @@ -103,7 +103,9 @@ | |||||
| -webkit-animation-delay: -0.8s; | -webkit-animation-delay: -0.8s; | ||||
| animation-delay: -0.8s; | animation-delay: -0.8s; | ||||
| } | } | ||||
| .left2{ | |||||
| margin-left: -2px; | |||||
| } | |||||
| @-webkit-keyframes sk-stretchdelay { | @-webkit-keyframes sk-stretchdelay { | ||||
| 0%, | 0%, | ||||
| 40%, | 40%, | ||||
| @@ -153,6 +155,8 @@ | |||||
| <form class="ui form" action="{{.Link}}" method="post"> | <form class="ui form" action="{{.Link}}" 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_names" value=""> | |||||
| <input type="hidden" id="ai_flaver_name" name="flaver_names" value=""> | |||||
| <h4 class="unite title ui header ">{{.i18n.Tr "repo.modelarts.train_job.basic_info"}}:</h4> | <h4 class="unite title ui header ">{{.i18n.Tr "repo.modelarts.train_job.basic_info"}}:</h4> | ||||
| <div class="required unite min_title inline field"> | <div class="required unite min_title inline field"> | ||||
| <label>{{.i18n.Tr "repo.modelarts.train_job.job_name"}}</label> | <label>{{.i18n.Tr "repo.modelarts.train_job.job_name"}}</label> | ||||
| @@ -163,18 +167,22 @@ | |||||
| <label for="description">{{.i18n.Tr "repo.modelarts.train_job.description"}} </label> | <label for="description">{{.i18n.Tr "repo.modelarts.train_job.description"}} </label> | ||||
| <textarea style="width: 80%;" id="description" name="description" rows="3" maxlength="255" placeholder={{.i18n.Tr "repo.modelarts.train_job.new_place"}} onchange="this.value=this.value.substring(0, 255)" onkeydown="this.value=this.value.substring(0, 255)" onkeyup="this.value=this.value.substring(0, 256)"></textarea> | <textarea style="width: 80%;" id="description" name="description" rows="3" maxlength="255" placeholder={{.i18n.Tr "repo.modelarts.train_job.new_place"}} onchange="this.value=this.value.substring(0, 255)" onkeydown="this.value=this.value.substring(0, 255)" onkeyup="this.value=this.value.substring(0, 256)"></textarea> | ||||
| </div> | </div> | ||||
| <!-- <h4 class="ui dividing header">{{.i18n.Tr "repo.modelarts.train_job.parameter_setting"}}</h4> | |||||
| <div class="inline field"> | |||||
| <label>{{.i18n.Tr "repo.modelarts.train_job.fast_parameter_setting"}}</label> | |||||
| <span> | |||||
| {{.i18n.Tr "repo.modelarts.train_job.fast_parameter_setting_config"}} | |||||
| <a class="item active parameter_config">{{.i18n.Tr "repo.modelarts.train_job.fast_parameter_setting_config_link"}}</a> | |||||
| </span> | |||||
| </div> --> | |||||
| <div class="ui divider"></div> | <div class="ui divider"></div> | ||||
| <h4 class="unite title ui header ">{{.i18n.Tr "repo.modelarts.train_job.parameter_setting"}}:</h4> | <h4 class="unite title ui header ">{{.i18n.Tr "repo.modelarts.train_job.parameter_setting"}}:</h4> | ||||
| <div class="required unite min_title inline field"> | |||||
| <label>{{.i18n.Tr "repo.modelarts.code_version"}}</label> | |||||
| <select class="ui dropdown width80 left2" id="code_version" name="branch_name"> | |||||
| {{range $k, $v :=.Branches}} | |||||
| <option name="branch_name" value="{{$v}}">{{$v}}</option> | |||||
| {{end}} | |||||
| </select> | |||||
| </div> | |||||
| <div class="required unite min_title inline fields" style="width: 90%;"> | <div class="required unite min_title inline fields" style="width: 90%;"> | ||||
| <label>{{.i18n.Tr "repo.modelarts.train_job.AI_driver"}} </label> | <label>{{.i18n.Tr "repo.modelarts.train_job.AI_driver"}} </label> | ||||
| <div class="field" style="flex: 1.5;"> | <div class="field" style="flex: 1.5;"> | ||||
| @@ -183,52 +191,19 @@ | |||||
| <option value="{{.Value}}">{{.Value}}</option> | <option value="{{.Value}}">{{.Value}}</option> | ||||
| {{end}} | {{end}} | ||||
| </select> | </select> | ||||
| </div> | </div> | ||||
| <div class="field" style="flex: 2;"> | |||||
| <div class="field" style="flex: 2;" id="engine_name"> | |||||
| <select class="ui dropdown width" id="trainjob_engine_versions" style='width: 100%;' name="engine_id"> | <select class="ui dropdown width" id="trainjob_engine_versions" style='width: 100%;' name="engine_id"> | ||||
| {{range .engine_versions}} | {{range .engine_versions}} | ||||
| <option name="engine_id" value="{{.ID}}">{{.Value}}</option> | <option name="engine_id" value="{{.ID}}">{{.Value}}</option> | ||||
| {{end}} | {{end}} | ||||
| </select> | </select> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <!-- <div class="required inline field"> | |||||
| <label>{{.i18n.Tr "repo.modelarts.train_job.algorithm_origin"}}</label> | |||||
| <div class="ui top attached tabular menu"> | |||||
| <a class="item active" data-tab="frame">{{svg "octicon-repo" 16}}{{.i18n.Tr "repo.modelarts.train_job.frames"}}</a> | |||||
| </div> | |||||
| <div class="ui bottom attached tab active segment" data-tab="frame"> | |||||
| <div class="required field"> | |||||
| <label>{{.i18n.Tr "repo.modelarts.train_job.AI_driver"}}</label> | |||||
| <div class="two fields"> | |||||
| <div class="field"> | |||||
| <select class="ui search dropdown" id="trainjob_engines" style='width:385px'> | |||||
| {{range .engines}} | |||||
| <option value="{{.Value}}">{{.Value}}</option> | |||||
| {{end}} | |||||
| </select> | |||||
| </div> | |||||
| <div class="field"> | |||||
| <select class="ui search dropdown" id="trainjob_engine_versions" style='width:385px' name="engine_id"> | |||||
| {{range .engine_versions}} | |||||
| <option name="engine_id" value="{{.ID}}">{{.Value}}</option> | |||||
| {{end}} | |||||
| </select> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div class="inline required field"> | |||||
| <label>{{.i18n.Tr "repo.modelarts.train_job.start_file"}}</label> | |||||
| <input name="boot_file" id="trainjob_boot_file" value="" tabindex="3" autofocus required maxlength="255"> | |||||
| <span> | |||||
| <i class="question circle icon link" data-content={{.i18n.Tr "repo.modelarts.train_job.boot_file_helper"}} data-position="right center" data-variation="mini"></i> | |||||
| </span> | |||||
| </div> | |||||
| </div> | |||||
| </div> --> | |||||
| <div class="inline unite min_title field required"> | <div class="inline unite min_title field required"> | ||||
| <label>{{.i18n.Tr "repo.modelarts.train_job.start_file"}}</label> | <label>{{.i18n.Tr "repo.modelarts.train_job.start_file"}}</label> | ||||
| {{if .bootFile}} | {{if .bootFile}} | ||||
| @@ -255,16 +230,12 @@ | |||||
| <div class="inline unite min_title field"> | <div class="inline unite min_title field"> | ||||
| <label>{{.i18n.Tr "repo.modelarts.train_job.run_parameter"}}</label> | <label>{{.i18n.Tr "repo.modelarts.train_job.run_parameter"}}</label> | ||||
| <!-- <i class="plus square outline icon"></i> --> | |||||
| <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;"></div> | <div class="dynamic field" style="margin-top: 1rem;"></div> | ||||
| <!-- <div class="dynamic field"> | |||||
| </div> --> | |||||
| </div> | </div> | ||||
| <!-- <h4 class="ui dividing header">{{.i18n.Tr "repo.modelarts.train_job.resource_setting"}}</h4> --> | |||||
| <div class="required field " style="display: none;"> | <div class="required field " style="display: none;"> | ||||
| <label>{{.i18n.Tr "repo.modelarts.train_job.resource_pool"}}</label> | <label>{{.i18n.Tr "repo.modelarts.train_job.resource_pool"}}</label> | ||||
| <select class="ui dropdown" id="trainjob_resource_pool" style='width:385px' name="pool_id"> | <select class="ui dropdown" id="trainjob_resource_pool" style='width:385px' name="pool_id"> | ||||
| @@ -290,7 +261,7 @@ | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div class="required unite min_title inline field"> | |||||
| <div class="required unite min_title inline field" id="flaver_name"> | |||||
| <label>{{.i18n.Tr "repo.modelarts.train_job.standard"}}</label> | <label>{{.i18n.Tr "repo.modelarts.train_job.standard"}}</label> | ||||
| <select class="ui dropdown width81" id="trainjob-flavor" style='width:385px' name="flavor"> | <select class="ui dropdown width81" id="trainjob-flavor" style='width:385px' name="flavor"> | ||||
| {{range .flavor_infos}} | {{range .flavor_infos}} | ||||
| @@ -302,36 +273,12 @@ | |||||
| <label>{{.i18n.Tr "repo.modelarts.train_job.amount_of_compute_node"}}</label> | <label>{{.i18n.Tr "repo.modelarts.train_job.amount_of_compute_node"}}</label> | ||||
| <div class="ui labeled input" style="width: 5%;"> | <div class="ui labeled input" style="width: 5%;"> | ||||
| <!-- <span class="min"><i class="minus icon"></i></span> --> | |||||
| <input style="border-radius: 0;text-align: center;" name="work_server_number" id="trainjob_work_server_num" tabindex="3" autofocus required maxlength="255" value="1" readonly> | <input style="border-radius: 0;text-align: center;" name="work_server_number" id="trainjob_work_server_num" tabindex="3" autofocus required maxlength="255" value="1" readonly> | ||||
| <!-- <span class="add"><i class="plus icon"></i></span> --> | |||||
| </div> | |||||
| <!-- <input name="work_server_number" id="trainjob_work_server_num" tabindex="3" autofocus required maxlength="255"> --> | |||||
| </div> | |||||
| <!-- | |||||
| <div class="inline field"> | |||||
| <div class="ui save checkbox"> | |||||
| <input name="is_save_para" type="checkbox"> | |||||
| <label>{{.i18n.Tr "repo.modelarts.train_job.query_whether_save_parameter"}} | |||||
| <span> | |||||
| <i class="question circle icon link" data-content={{.i18n.Tr "repo.modelarts.train_job.save_helper"}} data-position="right center" data-variation="mini"></i> | |||||
| </span> | |||||
| </label> | |||||
| </div> | |||||
| </div> | |||||
| <div class="disabled field" id="save_para"> | |||||
| <div class="field"> | |||||
| <label>{{.i18n.Tr "repo.modelarts.train_job.job_parameter_name"}}</label> | |||||
| <input name="parameter_template_name" id="parameter_template_name" tabindex="3" autofocus maxlength="255"> | |||||
| </div> | |||||
| <div class="field"> | |||||
| <label for="parameter_description">{{.i18n.Tr "repo.modelarts.train_job.parameter_description"}}</label> | |||||
| <textarea id="parameter_description" name="parameter_description" rows="2"></textarea> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| --> | |||||
| <div class="inline unite min_title field"> | <div class="inline unite min_title field"> | ||||
| <button class="ui create_train_job green button"> | <button class="ui create_train_job green button"> | ||||
| @@ -598,8 +545,15 @@ | |||||
| msg = JSON.stringify(msg) | msg = JSON.stringify(msg) | ||||
| $('#store_run_para').val(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) | |||||
| } | |||||
| $('.ui.create_train_job.green.button').click(function(e) { | $('.ui.create_train_job.green.button').click(function(e) { | ||||
| get_name() | |||||
| send_run_para() | send_run_para() | ||||
| validate() | validate() | ||||
| }) | }) | ||||
| @@ -1,139 +1,472 @@ | |||||
| {{template "base/head" .}} | {{template "base/head" .}} | ||||
| <style> | |||||
| .according-panel-heading{ | |||||
| box-sizing: border-box; | |||||
| padding: 8px 16px; | |||||
| color: #252b3a; | |||||
| background-color: #f2f5fc; | |||||
| line-height: 1.5; | |||||
| cursor: pointer; | |||||
| -moz-user-select: none; | |||||
| -webkit-user-select: none; | |||||
| -ms-user-select: none; | |||||
| -khtml-user-select: none; | |||||
| user-select: none; | |||||
| } | |||||
| .accordion-panel-title { | |||||
| margin-top: 0; | |||||
| margin-bottom: 0; | |||||
| color: #252b3a; | |||||
| } | |||||
| .accordion-panel-title-content{ | |||||
| vertical-align: middle; | |||||
| display: inline-block; | |||||
| width: calc(100% - 32px); | |||||
| cursor: default; | |||||
| } | |||||
| .acc-margin-bottom { | |||||
| margin-bottom: 5px; | |||||
| } | |||||
| .title_text { | |||||
| font-size: 12px; | |||||
| } | |||||
| .ac-display-inblock { | |||||
| display: inline-block; | |||||
| } | |||||
| .cti-mgRight-sm { | |||||
| margin-right: 8px; | |||||
| } | |||||
| .ac-text-normal { | |||||
| font-size: 14px; | |||||
| color: #575d6c; | |||||
| } | |||||
| .uc-accordionTitle-black { | |||||
| color: #333; | |||||
| } | |||||
| .accordion-border{ | |||||
| border:1px solid #cce2ff; | |||||
| } | |||||
| .padding0{ | |||||
| padding: 0 !important; | |||||
| } | |||||
| .content-pad{ | |||||
| padding: 15px 35px; | |||||
| } | |||||
| .content-margin{ | |||||
| margin:10px 5px ; | |||||
| } | |||||
| .tab_2_content { | |||||
| min-height: 360px; | |||||
| margin-left: 10px; | |||||
| } | |||||
| .ac-grid { | |||||
| display: block; | |||||
| *zoom: 1; | |||||
| } | |||||
| .ac-grid-col { | |||||
| float: left; | |||||
| width: 100%; | |||||
| } | |||||
| .ac-grid-col2 .ac-grid-col { | |||||
| width: 50%; | |||||
| } | |||||
| .ti-form { | |||||
| text-align: left; | |||||
| max-width: 100%; | |||||
| vertical-align: middle; | |||||
| } | |||||
| .ti-form>tbody { | |||||
| font-size: 12px; | |||||
| } | |||||
| .ti-form>tbody, .ti-form>tbody>tr { | |||||
| vertical-align: inherit; | |||||
| } | |||||
| .ti-text-form-label { | |||||
| padding-bottom: 20px; | |||||
| padding-right: 20px; | |||||
| color: #8a8e99; | |||||
| font-size: 12px; | |||||
| white-space: nowrap; | |||||
| width: 80px; | |||||
| line-height: 30px; | |||||
| } | |||||
| .ti-text-form-content{ | |||||
| line-height: 30px; | |||||
| padding-bottom: 20px; | |||||
| } | |||||
| .ti-form>tbody>tr>td { | |||||
| vertical-align: top; | |||||
| white-space: normal; | |||||
| } | |||||
| td, th { | |||||
| padding: 0; | |||||
| } | |||||
| .ac-grid-col .text-span { | |||||
| overflow: hidden; | |||||
| text-overflow: ellipsis; | |||||
| white-space: nowrap; | |||||
| } | |||||
| .redo-color{ | |||||
| color: #3291F8; | |||||
| } | |||||
| .ti-action-menu-item:not(:last-child){ | |||||
| margin-right: 10px; | |||||
| padding-right: 11px; | |||||
| text-decoration: none!important; | |||||
| color: #526ecc; | |||||
| cursor: pointer; | |||||
| display: inline-block; | |||||
| -moz-user-select: none; | |||||
| -webkit-user-select: none; | |||||
| -ms-user-select: none; | |||||
| -khtml-user-select: none; | |||||
| user-select: none; | |||||
| position: relative; | |||||
| } | |||||
| .ti-action-menu-item:not(:last-child):after { | |||||
| content: ""; | |||||
| display: inline-block; | |||||
| position: absolute; | |||||
| height: 12px; | |||||
| right: 0; | |||||
| top: 50%; | |||||
| -webkit-transform: translateY(-6px); | |||||
| -ms-transform: translateY(-6px); | |||||
| -o-transform: translateY(-6px); | |||||
| transform: translateY(-6px); | |||||
| border-right: 1px solid #dfe1e6; | |||||
| } | |||||
| .text-width80{ | |||||
| width: 100px; | |||||
| line-height: 30px; | |||||
| } | |||||
| .border-according{ | |||||
| border: 1px solid #dfe1e6; | |||||
| } | |||||
| .disabled { | |||||
| cursor: default; | |||||
| pointer-events: none; | |||||
| color: rgba(0,0,0,.6) !important; | |||||
| opacity: .45 !important; | |||||
| } | |||||
| .pad20{ | |||||
| border:0px !important; | |||||
| } | |||||
| .model_file_bread{ | |||||
| margin-bottom: -0.5rem !important; | |||||
| padding-left: 1rem; | |||||
| padding-top: 0.5rem ; | |||||
| } | |||||
| </style> | |||||
| <div class="repository"> | <div class="repository"> | ||||
| {{template "repo/header" .}} | {{template "repo/header" .}} | ||||
| <div class="repository new repo ui middle very relaxed page grid"> | |||||
| <div class="column"> | |||||
| {{template "base/alert" .}} | |||||
| <h4 class="ui top attached header"> | |||||
| <div class="ui two column grid"> | |||||
| <div class="column"> | |||||
| {{$.i18n.Tr "repo.modelarts.version_manage"}} | |||||
| <div class="ui container"> | |||||
| <h4 class="ui header" id="vertical-segment"> | |||||
| <!-- <a href="javascript:window.history.back();"><i class="arrow left icon"></i>返回</a> --> | |||||
| <div class="ui breadcrumb"> | |||||
| <a class="section" href="{{.RepoLink}}/cloudbrain"> | |||||
| {{.i18n.Tr "repo.cloudbrain"}} | |||||
| </a> | |||||
| <div class="divider"> / </div> | |||||
| <a class="section" href="{{$.RepoLink}}/modelarts/train-job"> | |||||
| {{$.i18n.Tr "repo.modelarts.train_job"}} | |||||
| </a> | |||||
| <div class="divider"> / </div> | |||||
| <div class="active section">{{.jobName}}</div> | |||||
| </div> | |||||
| </h4> | |||||
| {{range $k ,$v := .version_list_task}} | |||||
| <div class="ui accordion border-according" id="accordion{{.VersionName}}" data-repopath="{{$.RepoRelPath}}" data-jobid="{{.JobID}}" data-version="{{.VersionName}}"> | |||||
| <div class="{{if eq $k 0}}active{{end}} title padding0"> | |||||
| <div class="according-panel-heading"> | |||||
| <div class="accordion-panel-title"> | |||||
| <i class="dropdown icon"></i> | |||||
| <span class="accordion-panel-title-content"> | |||||
| <span> | |||||
| <div style="float: right;"> | |||||
| <!-- <a class="ti-action-menu-item {{if ne .Status "COMPLETED"}}disabled {{end}}">创建模型</a> --> | |||||
| {{$.CsrfTokenHtml}} | |||||
| {{if $.Permission.CanWrite $.UnitTypeCloudBrain}} | |||||
| <a class="ti-action-menu-item" href="{{$.RepoLink}}/modelarts/train-job/{{.JobID}}/create_version?version_name={{.VersionName}}">{{$.i18n.Tr "repo.modelarts.modify"}}</a> | |||||
| {{else}} | |||||
| <a class="ti-action-menu-item disabled" href="{{$.RepoLink}}/modelarts/train-job/{{.JobID}}/create_version?version_name={{.VersionName}}">{{$.i18n.Tr "repo.modelarts.modify"}}</a> | |||||
| {{end}} | |||||
| {{$.CsrfTokenHtml}} | |||||
| {{if $.Permission.CanWrite $.UnitTypeCloudBrain}} | |||||
| <a class="ti-action-menu-item {{if eq .Status "KILLED" "FAILED" "START_FAILED" "KILLING" "COMPLETED"}}disabled {{end}}" id="{{.VersionName}}-stop" onclick="stopVersion({{.VersionName}})">{{$.i18n.Tr "repo.stop"}}</a> | |||||
| {{else}} | |||||
| <a class="ti-action-menu-item disabled" id="{{.VersionName}}-stop" onclick="stopVersion({{.VersionName}})">{{$.i18n.Tr "repo.stop"}}</a> | |||||
| {{end}} | |||||
| {{$.CsrfTokenHtml}} | |||||
| {{if $.Permission.CanWrite $.UnitTypeCloudBrain}} | |||||
| <a class="ti-action-menu-item" onclick="deleteVersion({{.VersionName}})" style="color: #FF4D4F;">{{$.i18n.Tr "repo.delete"}}</a> | |||||
| {{else}} | |||||
| <a class="ti-action-menu-item disabled" onclick="deleteVersion({{.VersionName}})" style="color: #FF4D4F;">{{$.i18n.Tr "repo.delete"}}</a> | |||||
| {{end}} | |||||
| </div> | |||||
| <div class="ac-display-inblock title_text acc-margin-bottom"> | |||||
| <span class="cti-mgRight-sm">{{TimeSinceUnix1 .Cloudbrain.CreatedUnix}}</span> | |||||
| <span class="cti-mgRight-sm"> {{$.i18n.Tr "repo.modelarts.current_version"}}:{{.VersionName}}</span> | |||||
| <span class="cti-mgRight-sm"> {{$.i18n.Tr "repo.modelarts.parent_version"}}:{{.PreVersionName}}</span> | |||||
| <span class="cti-mgRight-sm ac-text-normal title_text">{{$.i18n.Tr "repo.modelarts.status"}}: | |||||
| <span id="{{.VersionName}}-status-span"><i id="icon" style="vertical-align: middle;" class="{{.Status}}"></i><span id="text" style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span> | |||||
| </span> | |||||
| <span class="ac-text-normal title_text">{{$.i18n.Tr "repo.modelarts.train_job.dura_time"}}:</span> | |||||
| <span class="cti-mgRight-sm uc-accordionTitle-black" id="{{.VersionName}}-duration-span">{{.TrainJobDuration}}</span> | |||||
| <span data-tooltip="刷新" style="cursor: pointer;" data-inverted="" onclick="refreshStatus({{.VersionName}})"><i class="redo icon redo-color"></i></span> | |||||
| </div> | |||||
| </span> | |||||
| </span> | |||||
| </div> | </div> | ||||
| <div class="column right aligned"> | |||||
| <a href="javascript:window.history.back();">{{svg "octicon-reply" 16}}{{$.i18n.Tr "repo.modelarts.back"}}</a> | |||||
| </div> | |||||
| </div> | |||||
| <div class="{{if eq $k 0}}active{{end}} content accordion-border"> | |||||
| <div class="content-pad"> | |||||
| <div class="ui pointing secondary menu"> | |||||
| <a class="active item" data-tab="first{{$k}}">{{$.i18n.Tr "repo.modelarts.train_job.config"}}</a> | |||||
| <a class="item" data-tab="second{{$k}}" onclick="loadLog({{.VersionName}})">{{$.i18n.Tr "repo.modelarts.log"}}</a> | |||||
| <a class="item" data-tab="third{{$k}}" onclick="loadModelFile({{.VersionName}},'','','init')">{{$.i18n.Tr "repo.model_download"}}</a> | |||||
| </div> | </div> | ||||
| </div> | |||||
| </h4> | |||||
| <div class="ui tab active" data-tab="first{{$k}}"> | |||||
| <div style="padding-top: 10px;"> | |||||
| <div class="tab_2_content"> | |||||
| <div class="ac-grid ac-grid-col2"> | |||||
| <div class="ac-grid-col"> | |||||
| <table class="ti-form"> | |||||
| <tbody class="ti-text-form"> | |||||
| <tr class="ti-no-ng-animate"> | |||||
| <td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
| {{$.i18n.Tr "repo.cloudbrain_task"}} | |||||
| </td> | |||||
| <div class="ui attached segment"> | |||||
| <div class="ui style accordion"> | |||||
| <div class="title active"> | |||||
| <i class="dropdown icon"></i> | |||||
| {{$.i18n.Tr "repo.modelarts.train_job.version"}} | |||||
| </div> | |||||
| <div class="content active"> | |||||
| <div class="ui container"> | |||||
| <div class="ui top attached tabular menu"> | |||||
| <a class="item active" data-tab="configs">{{$.i18n.Tr "repo.modelarts.train_job.config"}}</a> | |||||
| <a class="item logs" data-tab="logs">{{$.i18n.Tr "repo.modelarts.log"}}</a> | |||||
| <!-- <a class="item" data-tab="resources">资源占用情况</a> --> | |||||
| </div> | |||||
| <div class="ui bottom attached tab segment active" data-tab="configs"> | |||||
| <div> | |||||
| <div class="ui yellow segment"> | |||||
| <table class="ui celled striped table"> | |||||
| <thead> | |||||
| <tr> <th colspan="2"> {{.i18n.Tr "repo.modelarts.train_job.basic_info"}} </th> </tr> | |||||
| </thead> | |||||
| <tbody> | |||||
| <tr> | |||||
| <td class="four wide"> {{.i18n.Tr "repo.modelarts.train_job.job_name"}} </td> | |||||
| <td>{{.result.JobName}}</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td class="four wide"> {{.i18n.Tr "repo.modelarts.train_job.job_status"}} </td> | |||||
| <td>{{.result.Status}}</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td class="four wide"> {{.i18n.Tr "repo.modelarts.train_job.version"}} </td> | |||||
| <td>{{.result.VersionName}}</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td class="four wide"> {{.i18n.Tr "repo.modelarts.train_job.start_time"}} </td> | |||||
| <td>{{.result.CreateTime}}</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td class="four wide"> {{.i18n.Tr "repo.modelarts.train_job.dura_time"}} </td> | |||||
| <td>{{.result.TrainJobDuration}}</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td class="four wide"> {{.i18n.Tr "repo.modelarts.train_job.description"}} </td> | |||||
| <td>{{.result.Description}}</td> | |||||
| </tr> | |||||
| </tbody> | |||||
| </table> | |||||
| </div> | |||||
| <div class="ui green segment"> | |||||
| <table class="ui celled striped table"> | |||||
| <thead> | |||||
| <tr> <th colspan="2"> {{.i18n.Tr "repo.modelarts.train_job.parameter_setting_info"}} </th> </tr> | |||||
| </thead> | |||||
| <tbody> | |||||
| <tr> | |||||
| <td class="four wide"> {{.i18n.Tr "repo.modelarts.train_job.AI_driver"}} </td> | |||||
| <td>{{.result.EngineName}} | {{.result.EngineVersion}}</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td class="four wide"> {{.i18n.Tr "repo.modelarts.train_job.start_file"}}</td> | |||||
| <td>{{.result.BootFileUrl}}</td> | |||||
| <td class="ti-text-form-content"> | |||||
| <div class="text-span text-span-w"> | |||||
| {{.JobName}} | |||||
| </div> | |||||
| </td> | |||||
| </tr> | |||||
| <tr class="ti-no-ng-animate"> | |||||
| <td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
| {{$.i18n.Tr "repo.modelarts.status"}} | |||||
| </td> | |||||
| <td class="ti-text-form-content"> | |||||
| <div class="text-span text-span-w" id="{{.VersionName}}-status"> | |||||
| {{.Status}} | |||||
| </div> | |||||
| </td> | |||||
| </tr> | |||||
| <tr class="ti-no-ng-animate"> | |||||
| <td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
| {{$.i18n.Tr "repo.modelarts.run_version"}} | |||||
| </td> | |||||
| <td class="ti-text-form-content"> | |||||
| <div class="text-span text-span-w"> | |||||
| {{.VersionName}} | |||||
| </div> | |||||
| </td> | |||||
| </tr> | |||||
| <tr class="ti-no-ng-animate"> | |||||
| <td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
| {{$.i18n.Tr "repo.modelarts.train_job.start_time"}} | |||||
| </td> | |||||
| <td class="ti-text-form-content"> | |||||
| <div class="text-span text-span-w"> | |||||
| <span style="font-size: 12px;" class="">{{TimeSinceUnix1 .Cloudbrain.CreatedUnix}}</span> | |||||
| </div> | |||||
| </td> | |||||
| </tr> | |||||
| <tr class="ti-no-ng-animate"> | |||||
| <td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
| {{$.i18n.Tr "repo.modelarts.train_job.dura_time"}} | |||||
| </td> | |||||
| <td class="ti-text-form-content"> | |||||
| <div class="text-span text-span-w" id="{{.VersionName}}-duration"> | |||||
| {{.TrainJobDuration}} | |||||
| </div> | |||||
| </td> | |||||
| </tr> | |||||
| <tr class="ti-no-ng-animate"> | |||||
| <td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
| {{$.i18n.Tr "repo.modelarts.train_job.standard"}} | |||||
| </td> | |||||
| <td class="ti-text-form-content"> | |||||
| <div class="text-span text-span-w"> | |||||
| {{.FlavorName}} | |||||
| </div> | |||||
| </td> | |||||
| </tr> | |||||
| <tr class="ti-no-ng-animate"> | |||||
| <td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
| {{$.i18n.Tr "repo.modelarts.train_job.compute_node"}} | |||||
| </td> | |||||
| <td class="ti-text-form-content"> | |||||
| <div class="text-span text-span-w"> | |||||
| {{.WorkServerNumber}} | |||||
| </div> | |||||
| </td> | |||||
| </tr> | |||||
| </tbody> | |||||
| </table> | |||||
| </div> | |||||
| <div class="ac-grid-col"> | |||||
| <table class="ti-form"> | |||||
| <tbody class="ti-text-form"> | |||||
| <tr class="ti-no-ng-animate"> | |||||
| <td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
| {{$.i18n.Tr "repo.modelarts.train_job.AI_driver"}} | |||||
| </td> | |||||
| <td class="ti-text-form-content"> | |||||
| <div class="text-span text-span-w"> | |||||
| {{.EngineName}} | |||||
| </div> | |||||
| </td> | |||||
| </tr> | </tr> | ||||
| <tr> | |||||
| <td class="four wide"> {{.i18n.Tr "repo.modelarts.train_job.dataset"}} </td> | |||||
| <td>{{.result.DatasetName}}</td> | |||||
| <tr class="ti-no-ng-animate"> | |||||
| <td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
| {{$.i18n.Tr "repo.modelarts.code_version"}} | |||||
| </td> | |||||
| <td class="ti-text-form-content"> | |||||
| <div class="text-span text-span-w"> | |||||
| {{.BranchName}} | |||||
| </div> | |||||
| </td> | |||||
| </tr> | </tr> | ||||
| <tr> | |||||
| <td class="four wide"> {{.i18n.Tr "repo.modelarts.train_job.run_parameter"}} </td> | |||||
| <td>{{.result.Parameter}}</td> | |||||
| <tr class="ti-no-ng-animate"> | |||||
| <td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
| {{$.i18n.Tr "repo.modelarts.train_job.start_file"}} | |||||
| </td> | |||||
| <td class="ti-text-form-content"> | |||||
| <div class="text-span text-span-w"> | |||||
| {{.BootFile}} | |||||
| </div> | |||||
| </td> | |||||
| </tr> | </tr> | ||||
| </tbody> | |||||
| </table> | |||||
| </div> | |||||
| <div class="ui blue segment"> | |||||
| <table class="ui celled striped table"> | |||||
| <thead> | |||||
| <tr> <th colspan="2"> {{.i18n.Tr "repo.modelarts.train_job.resource_setting_info"}} </th> </tr> | |||||
| </thead> | |||||
| <tbody> | |||||
| <tr> | |||||
| <td class="four wide"> {{.i18n.Tr "repo.modelarts.train_job.resource_pool"}} </td> | |||||
| <td>{{.result.PoolName}}</td> | |||||
| <tr class="ti-no-ng-animate"> | |||||
| <td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
| {{$.i18n.Tr "repo.modelarts.train_job.train_dataset"}} | |||||
| </td> | |||||
| <td class="ti-text-form-content"> | |||||
| <div class="text-span text-span-w"> | |||||
| {{.DatasetName}} | |||||
| </div> | |||||
| </td> | |||||
| </tr> | </tr> | ||||
| <tr> | |||||
| <td class="four wide"> {{.i18n.Tr "repo.modelarts.train_job.amount_of_compute_node"}}</td> | |||||
| <td>{{.result.WorkServerNum}}</td> | |||||
| <tr class="ti-no-ng-animate"> | |||||
| <td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
| {{$.i18n.Tr "repo.modelarts.train_job.run_parameter"}} | |||||
| </td> | |||||
| <td class="ti-text-form-content"> | |||||
| <div class="text-span text-span-w"> | |||||
| {{.Parameters}} | |||||
| </div> | |||||
| </td> | |||||
| </tr> | </tr> | ||||
| <tr> | |||||
| <td class="four wide"> {{.i18n.Tr "repo.modelarts.train_job.NAS_mount_path"}} </td> | |||||
| <td>{{.result.NasMountPath}}</td> | |||||
| <!-- <tr class="ti-no-ng-animate"> | |||||
| <td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
| 训练输出位置 | |||||
| </td> | |||||
| <td class="ti-text-form-content"> | |||||
| <div class="text-span text-span-w"> | |||||
| {{.TrainUrl}} | |||||
| </div> | |||||
| </td> | |||||
| </tr> --> | |||||
| <tr class="ti-no-ng-animate"> | |||||
| <td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
| {{$.i18n.Tr "repo.modelarts.train_job.description"}} | |||||
| </td> | |||||
| <td class="ti-text-form-content"> | |||||
| <div class="text-span text-span-w"> | |||||
| {{.Cloudbrain.Description}} | |||||
| </div> | |||||
| </td> | |||||
| </tr> | </tr> | ||||
| </tbody> | </tbody> | ||||
| </table> | </table> | ||||
| </div> | </div> | ||||
| </div> | |||||
| </div> | </div> | ||||
| <div class="ui bottom attached tab segment" data-tab="logs"> | |||||
| <div class="ui message" style="display: none;"> | |||||
| <div class="header"> | |||||
| </div> | |||||
| </div> | |||||
| <div class="ui top attached segment" style="background: #f0f0f0;"> | |||||
| <div class="center aligned"> | |||||
| <label>{{$.i18n.Tr "repo.modelarts.log"}}:</label> | |||||
| <span class="fitted file_name">{{.log_file_name}}</span> | |||||
| <input type="hidden" name="file_name" value={{.log_file_name}}> | |||||
| <input type="hidden" name="start_line" value={{.log.StartLine}}> | |||||
| <input type="hidden" name="end_line" value={{.log.EndLine}}> | |||||
| </div> | |||||
| </div> | |||||
| <div class="ui attached segment log" style="height: 300px !important; overflow: auto;"> | |||||
| <pre>{{.log.Content}}</pre> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div class="ui tab" data-tab="second{{$k}}"> | |||||
| <div> | |||||
| <div class="ui message{{.VersionName}}" style="display: none;"> | |||||
| <div id="header"></div> | |||||
| </div> | |||||
| <div class="ui top attached segment" style="background: #f0f0f0;"> | |||||
| <div class="center aligned"> | |||||
| <label>{{$.i18n.Tr "repo.modelarts.log"}}:</label> | |||||
| <!-- <span class="fitted file_name">{{.}}</span> --> | |||||
| <!-- <input type="hidden" name="file_name" value> | |||||
| <input type="hidden" name="start_line" value> | |||||
| <input type="hidden" name="end_line" value> --> | |||||
| </div> | |||||
| </div> | </div> | ||||
| </div> | |||||
| <div class="ui attached segment log" onscroll="logScroll({{.VersionName}})" id="log{{.VersionName}}" style="height: 300px !important; overflow: auto;"> | |||||
| <!-- <input type="hidden" class="version_name" name="version_name" value={{.VersionName}}> --> | |||||
| <input type="hidden" name="end_line" value> | |||||
| <input type="hidden" name="start_line" value> | |||||
| <pre id="log_file{{.VersionName}}"></pre> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div class="ui tab" data-tab="third{{$k}}"> | |||||
| <input type="hidden" name="model{{.VersionName}}" value="-1"> | |||||
| <input type="hidden" name="modelback{{.VersionName}}" value="-1"> | |||||
| <div class='ui breadcrumb model_file_bread' id='file_breadcrumb{{.VersionName}}'> | |||||
| <div class="active section">{{.VersionName}}</div> | |||||
| <div class="divider"> / </div> | |||||
| </div> | |||||
| <div id="dir_list{{.VersionName}}"> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| {{end}} | |||||
| </div> | |||||
| <!-- 确认模态框 --> | |||||
| <div id="deletemodel"> | |||||
| <div class="ui basic modal"> | |||||
| <div class="ui icon header"> | |||||
| <i class="trash icon"></i> 删除任务 | |||||
| </div> | |||||
| <div class="content"> | |||||
| <p>你确认删除该任务么?此任务一旦删除不可恢复。</p> | |||||
| </div> | |||||
| <div class="actions"> | |||||
| <div class="ui red basic inverted cancel button"> | |||||
| <i class="remove icon"></i> 取消操作 | |||||
| </div> | |||||
| <div class="ui green basic inverted ok button"> | |||||
| <i class="checkmark icon"></i> 确定操作 | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| @@ -142,59 +475,274 @@ | |||||
| {{template "base/footer" .}} | {{template "base/footer" .}} | ||||
| <script> | <script> | ||||
| console.log({{.version_list_task}}) | |||||
| $('.menu .item').tab() | $('.menu .item').tab() | ||||
| $('.ui.style.accordion').accordion(); | |||||
| // $('.ui.style.accordion').accordion(); | |||||
| var userName | |||||
| var repoPath | |||||
| var jobID | |||||
| $(document).ready(function(){ | $(document).ready(function(){ | ||||
| var url = window.location.href; | |||||
| var urlArr = url.split('/') | |||||
| $('.ui.accordion').accordion({selector:{trigger:'.icon'}}); | |||||
| }); | |||||
| $(document).ready(function(){ | |||||
| $('.secondary.menu .item').tab(); | |||||
| }); | |||||
| let userName | |||||
| let repoPath | |||||
| let jobID | |||||
| $(document).ready(function(){ | |||||
| let url = window.location.href; | |||||
| let urlArr = url.split('/') | |||||
| userName = urlArr.slice(-5)[0] | userName = urlArr.slice(-5)[0] | ||||
| repoPath = urlArr.slice(-4)[0] | repoPath = urlArr.slice(-4)[0] | ||||
| jobID = urlArr.slice(-1)[0] | jobID = urlArr.slice(-1)[0] | ||||
| }) | }) | ||||
| function stopBubbling(e) { | |||||
| e = window.event || e; | |||||
| if (e.stopPropagation) { | |||||
| e.stopPropagation(); //阻止事件 冒泡传播 | |||||
| } else { | |||||
| e.cancelBubble = true; //ie兼容 | |||||
| } | |||||
| } | |||||
| // let timeid = window.setInterval(refreshStatus(version_name), 30000); | |||||
| // document.ready(refreshStatus(version_name)) | |||||
| let timeid = window.setInterval(loadJobStatus, 30000); | |||||
| $(document).ready(loadJobStatus); | |||||
| $(".log").scroll(function () { | |||||
| var scrollTop = $(this)[0].scrollTop; // 滚动距离 | |||||
| var scrollHeight = $(this)[0].scrollHeight; // 文档高度 | |||||
| var divHeight = $(this).height(); // 可视区高度 | |||||
| var file_name = $('input[name=file_name]').val() | |||||
| function renderSize(value){ | |||||
| if(null==value||value==''){ | |||||
| return "0 Bytes"; | |||||
| } | |||||
| var unitArr = new Array("Bytes","KB","MB","GB","TB","PB","EB","ZB","YB"); | |||||
| var index=0; | |||||
| var srcsize = parseFloat(value); | |||||
| index=Math.floor(Math.log(srcsize)/Math.log(1024)); | |||||
| var size =srcsize/Math.pow(1024,index); | |||||
| size=size.toFixed(2);//保留的小数位数 | |||||
| return size+unitArr[index]; | |||||
| } | |||||
| function loadJobStatus() { | |||||
| $(".ui.accordion.border-according").each((index, job) => { | |||||
| const jobID = job.dataset.jobid; | |||||
| const repoPath = job.dataset.repopath; | |||||
| const versionname = job.dataset.version | |||||
| if (job.textContent.trim() == 'IMAGE_FAILED' || job.textContent.trim() == 'SUBMIT_FAILED' || job.textContent.trim() == 'DELETE_FAILED' | |||||
| || job.textContent.trim() == 'KILLED' || job.textContent.trim() == 'COMPLETED' || job.textContent.trim() == 'FAILED' | |||||
| || job.textContent.trim() == 'CANCELED' || job.textContent.trim() == 'LOST') { | |||||
| return | |||||
| } | |||||
| let stopArray=["KILLED","FAILED","START_FAILED","KILLING","COMPLETED"] | |||||
| $.get(`/api/v1/repos/${repoPath}/modelarts/train-job/${jobID}?version_name=${versionname}`, (data) => { | |||||
| $(`#${versionname}-duration-span`).text(data.JobDuration) | |||||
| $(`#${versionname}-status-span span`).text(data.JobStatus) | |||||
| $(`#${versionname}-status-span i`).attr("class",data.JobStatus) | |||||
| // detail status and duration | |||||
| $('#'+versionname+'-duration').text(data.JobDuration) | |||||
| $('#'+versionname+'-status').text(data.JobStatus) | |||||
| if(stopArray.includes(data.JobStatus)){ | |||||
| $('#'+versionname+'-stop').addClass('disabled') | |||||
| } | |||||
| }).fail(function(err) { | |||||
| console.log(err); | |||||
| }); | |||||
| }); | |||||
| }; | |||||
| function refreshStatus(version_name){ | |||||
| $.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}?version_name=${version_name}`,(data)=>{ | |||||
| console.log(data) | |||||
| // header status and duration | |||||
| $(`#${version_name}-duration-span`).text(data.JobDuration) | |||||
| $(`#${version_name}-status-span span`).text(data.JobStatus) | |||||
| $(`#${version_name}-status-span i`).attr("class",data.JobStatus) | |||||
| // detail status and duration | |||||
| $('#'+version_name+'-duration').text(data.JobDuration) | |||||
| $('#'+version_name+'-status').text(data.JobStatus) | |||||
| if(parseInt(scrollTop) + divHeight + 29 == scrollHeight){ | |||||
| var end_line = $('input[name=end_line]').val() | |||||
| $.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?file_name=${file_name}&base_line=${end_line}&order=desc`, (data) => { | |||||
| if (data.lines == 0){ | |||||
| $('.header').text('您已翻阅至日志底部') | |||||
| $('.message').css('display', 'block') | |||||
| }).fail(function(err) { | |||||
| console.log(err); | |||||
| }); | |||||
| stopBubbling(arguments.callee.caller.arguments[0]) | |||||
| } | |||||
| function deleteVersion(version_name){ | |||||
| stopBubbling(arguments.callee.caller.arguments[0]) | |||||
| let flag = 1; | |||||
| $('.ui.basic.modal').modal({ | |||||
| onDeny: function() { | |||||
| flag = false | |||||
| }, | |||||
| onApprove: function() { | |||||
| $.post(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/del_version`,{version_name:version_name},(data)=>{ | |||||
| $('#accordion'+version_name).remove() | |||||
| }).fail(function(err) { | |||||
| console.log(err); | |||||
| }); | |||||
| flag = true | |||||
| }, | |||||
| onHidden: function() { | |||||
| if (flag == false) { | |||||
| $('.alert').html('您已取消操作').removeClass('alert-success').addClass('alert-danger').show().delay(1500).fadeOut(); | |||||
| } | |||||
| } | |||||
| }) | |||||
| .modal('show') | |||||
| } | |||||
| function stopVersion(version_name){ | |||||
| stopBubbling(arguments.callee.caller.arguments[0]) | |||||
| $.post(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/stop_version`,{version_name:version_name},(data)=>{ | |||||
| if(data.StatusOK===0){ | |||||
| $('#'+version_name+'-stop').addClass('disabled') | |||||
| refreshStatus(version_name) | |||||
| } | |||||
| }).fail(function(err) { | |||||
| console.log(err); | |||||
| }); | |||||
| } | |||||
| function loadLog(version_name){ | |||||
| $.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?version_name=${version_name}&lines=20&order=asc`, (data) => { | |||||
| $('input[name=end_line]').val(data.EndLine) | |||||
| $('input[name=start_line]').val(data.StartLine) | |||||
| $(`#log_file${version_name}`).text(data.Content) | |||||
| }).fail(function(err) { | |||||
| console.log(err); | |||||
| }); | |||||
| } | |||||
| function loadModelFile(version_name,parents,filename,init){ | |||||
| parents = parents || '' | |||||
| filename = filename || '' | |||||
| init = init || '' | |||||
| $.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/model_list?version_name=${version_name}&parentDir=${parents}`, (data) => { | |||||
| $(`#dir_list${version_name}`).empty() | |||||
| renderDir(data,version_name) | |||||
| if(init==="init"){ | |||||
| $(`input[name=model${version_name}]`).val("") | |||||
| $(`input[name=modelback${version_name}]`).val(version_name) | |||||
| $(`#file_breadcrumb${version_name}`).empty() | |||||
| let htmlBread = "" | |||||
| htmlBread += `<div class='active section'>${version_name}</div>` | |||||
| htmlBread += "<div class='divider'> / </div>" | |||||
| $(`#file_breadcrumb${version_name}`).append(htmlBread) | |||||
| }else{ | |||||
| renderBrend(version_name,parents,filename,init) | |||||
| } | |||||
| }).fail(function(err) { | |||||
| console.log(err,version_name); | |||||
| }); | |||||
| } | |||||
| function renderBrend(version_name,parents,filename,init){ | |||||
| if(init=="folder"){ | |||||
| let htmlBrend = "" | |||||
| let sectionName=$(`#file_breadcrumb${version_name} .active.section`).text() | |||||
| let parents1 = $(`input[name=model${version_name}]`).val() | |||||
| let filename1 = $(`input[name=modelback${version_name}]`).val() | |||||
| if(parents1===""){ | |||||
| $(`#file_breadcrumb${version_name} .active.section`).replaceWith(`<a class='section' onclick="loadModelFile('${version_name}','${parents1}','','init')">${sectionName}</a>`) | |||||
| }else{ | |||||
| $(`#file_breadcrumb${version_name} .active.section`).replaceWith(`<a class='section' onclick="loadModelFile('${version_name}','${parents1}','${filename1}')">${sectionName}</a>`) | |||||
| } | |||||
| htmlBrend += `<div class='active section'>${filename}</div>` | |||||
| htmlBrend += "<div class='divider'> / </div>" | |||||
| $(`#file_breadcrumb${version_name}`).append(htmlBrend) | |||||
| $(`input[name=model${version_name}]`).val(parents) | |||||
| $(`input[name=modelback${version_name}]`).val(filename) | |||||
| }else{ | |||||
| $(`input[name=model${version_name}]`).val(parents) | |||||
| $(`input[name=modelback${version_name}]`).val(filename) | |||||
| $(`#file_breadcrumb${version_name} a.section:contains(${filename})`).nextAll().remove() | |||||
| $(`#file_breadcrumb${version_name} a.section:contains(${filename})`).replaceWith(`<div class='active section'>${filename}</div>`) | |||||
| $(`#file_breadcrumb${version_name} div.section:contains(${filename})`).append("<div class='divider'> / </div>") | |||||
| } | |||||
| } | |||||
| function renderDir(data,version_name){ | |||||
| let html="" | |||||
| html += "<div class='ui grid' style='margin:0;'>" | |||||
| html += "<div class='row' style='padding: 0;'>" | |||||
| html += "<div class='ui sixteen wide column' style='padding:1rem;'>" | |||||
| html += "<div class='dir list'>" | |||||
| html += "<table id='repo-files-table' class='ui single line table pad20'>" | |||||
| html += '<tbody>' | |||||
| // html += "</tbody>" | |||||
| for(let i=0;i<data.Dirs.length;i++){ | |||||
| let dirs_size = renderSize(data.Dirs[i].Size) | |||||
| html += "<tr>" | |||||
| html += "<td class='name six wid'>" | |||||
| html += "<span class='truncate'>" | |||||
| html += "<span class='octicon octicon-file-directory'>" | |||||
| html += "</span>" | |||||
| if(data.Dirs[i].IsDir){ | |||||
| html += `<a onclick="loadModelFile('${version_name}','${data.Dirs[i].ParenDir}','${data.Dirs[i].FileName}','folder')">` | |||||
| html += "<span class='fitted'><i class='folder icon' width='16' height='16' aria-hidden='true'></i>" + data.Dirs[i].FileName + "</span>" | |||||
| }else{ | |||||
| html += `<a href='${location.href}/download_model?parentDir=&fileName=${data.Dirs[i].FileName}&jobName=${data.task.JobName}'>` | |||||
| html += "<span class='fitted'><i class='file icon' width='16' height='16' aria-hidden='true'></i>" + data.Dirs[i].FileName + "</span>" | |||||
| } | |||||
| html += '</a>' | |||||
| html += "</span>" | |||||
| html += "</td>" | |||||
| html += "<td class='message seven wide'>" | |||||
| html += "<span class='truncate has-emoji'>"+ `${dirs_size}` + "</span>" | |||||
| html += "</td>" | |||||
| html += "<td class='text right age three wide'>" | |||||
| html += "<span class='truncate has-emoji'>" + data.Dirs[i].ModTime + "</span>" | |||||
| html += "</td>" | |||||
| html += "</tr>" | |||||
| } | |||||
| html += "</tbody>" | |||||
| html += "</table>" | |||||
| html += "</div>" | |||||
| html += "</div>" | |||||
| html += "</div>" | |||||
| html += "</div>" | |||||
| $(`#dir_list${version_name}`).append(html) | |||||
| } | |||||
| // $(`.log{}`).scroll() | |||||
| function logScroll(version_name) { | |||||
| let scrollTop = $(`#log${version_name}`)[0].scrollTop; // 滚动距离 | |||||
| let scrollHeight = $(`#log${version_name}`)[0].scrollHeight; // 文档高度 | |||||
| let divHeight = $(`#log${version_name}`).height(); // 可视区高度 | |||||
| // let version_name=$(this).find('input[name=version_name]').val() | |||||
| console.log("scrollTo,scrollHeight,divHeight",scrollTop,scrollHeight,divHeight) | |||||
| if(parseInt(scrollTop) + divHeight + 18 == scrollHeight){ | |||||
| let end_line = $(`#log${version_name} input[name=end_line]`).val() | |||||
| $.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?version_name=${version_name}&base_line=${end_line}&order=desc`, (data) => { | |||||
| if (data.Lines == 0){ | |||||
| $(`.message${version_name} #header`).text('您已翻阅至日志底部') | |||||
| $(`.message${version_name}`).css('display', 'block') | |||||
| setTimeout(function(){ | setTimeout(function(){ | ||||
| $('.message').css('display', 'none') | |||||
| $(`.message${version_name}`).css('display', 'none') | |||||
| }, 1000) | }, 1000) | ||||
| }else{ | }else{ | ||||
| $('input[name=end_line]').val(data.EndLine) | |||||
| $('.log').append('<pre>' + data.Content) | |||||
| $(`#log${version_name} input[name=end_line]`).val(data.EndLine) | |||||
| $(`#log${version_name}`).append('<pre>' + data.Content) | |||||
| } | } | ||||
| }).fail(function(err) { | }).fail(function(err) { | ||||
| console.log(err); | console.log(err); | ||||
| }); | }); | ||||
| } | } | ||||
| if(scrollTop == 0){ | if(scrollTop == 0){ | ||||
| var start_line = $('input[name=start_line]').val() | |||||
| $.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?file_name=${file_name}&base_line=${start_line}&order=asc`, (data) => { | |||||
| if (data.lines == 0){ | |||||
| $('.header').text('您已翻阅至日志顶部') | |||||
| $('.message').css('display', 'block') | |||||
| let start_line = $(`#log${version_name} input[name=start_line]`).val() | |||||
| $.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?version_name=${version_name}&base_line=${start_line}&order=asc`, (data) => { | |||||
| if (data.Lines == 0){ | |||||
| $(`.message${version_name} #header`).text('您已翻阅至日志顶部') | |||||
| $(`.message${version_name}`).css('display', 'block') | |||||
| setTimeout(function(){ | setTimeout(function(){ | ||||
| $('.message').css('display', 'none') | |||||
| $(`.message${version_name}`).css('display', 'none') | |||||
| }, 1000) | }, 1000) | ||||
| }else{ | }else{ | ||||
| $('input[name=start_line]').val(data.StartLine) //如果变动就改变所对应的值 | |||||
| $(".log").prepend('<pre>' + data.Content) | |||||
| $(`#log${version_name} input[name=start_line]`).val(data.StartLine) //如果变动就改变所对应的值 | |||||
| $(`#log${version_name}`).prepend('<pre>' + data.Content) | |||||
| } | } | ||||
| }).fail(function(err) { | }).fail(function(err) { | ||||
| console.log(err); | console.log(err); | ||||
| }); | }); | ||||
| } | } | ||||
| }) | |||||
| } | |||||
| </script> | </script> | ||||
| @@ -0,0 +1,628 @@ | |||||
| {{template "base/head" .}} | |||||
| <style> | |||||
| .unite{ | |||||
| font-family: SourceHanSansSC-medium !important; | |||||
| color: rgba(16, 16, 16, 100) !important; | |||||
| } | |||||
| .title{ | |||||
| font-size: 16px !important; | |||||
| padding-left: 3rem !important; | |||||
| } | |||||
| .min_title{ | |||||
| font-size: 14px !important; | |||||
| padding-left: 6rem !important; | |||||
| margin-bottom: 2rem !important; | |||||
| } | |||||
| .width{ | |||||
| width:100% !important; | |||||
| } | |||||
| .width80{ | |||||
| width: 80.7% !important; | |||||
| margin-left: 10px; | |||||
| } | |||||
| .width85{ | |||||
| width: 85% !important; | |||||
| margin-left: 4.5rem !important; | |||||
| } | |||||
| .width81{ | |||||
| margin-left: 1.5rem; | |||||
| width: 81% !important; | |||||
| } | |||||
| .add{font-size: 18px; | |||||
| padding: 0.5rem; | |||||
| border: 1px solid rgba(187, 187, 187, 100); | |||||
| border-radius: 0px 5px 5px 0px; | |||||
| line-height: 21px; | |||||
| text-align: center; | |||||
| color: #C2C7CC; | |||||
| } | |||||
| .min{ | |||||
| font-size: 18px; | |||||
| padding: 0.5rem; | |||||
| border: 1px solid rgba(187, 187, 187, 100); | |||||
| border-radius: 5px 0px 0px 5px; | |||||
| line-height: 21px; | |||||
| text-align: center; | |||||
| color: #C2C7CC;" | |||||
| } | |||||
| #mask { | |||||
| position: fixed; | |||||
| top: 0px; | |||||
| left: 0px; | |||||
| right: 0px; | |||||
| bottom: 0px; | |||||
| filter: alpha(opacity=60); | |||||
| background-color: #777; | |||||
| z-index: 1000; | |||||
| display: none; | |||||
| opacity: 0.8; | |||||
| -moz-opacity: 0.5; | |||||
| padding-top: 100px; | |||||
| color: #000000 | |||||
| } | |||||
| /* 加载圈css效果图 */ | |||||
| #loadingPage { | |||||
| margin: 200px auto; | |||||
| width: 50px; | |||||
| height: 40px; | |||||
| text-align: center; | |||||
| font-size: 10px; | |||||
| display: block; | |||||
| } | |||||
| #loadingPage>div { | |||||
| background-color: green; | |||||
| height: 100%; | |||||
| width: 6px; | |||||
| display: inline-block; | |||||
| -webkit-animation: sk-stretchdelay 1.2s infinite ease-in-out; | |||||
| animation: sk-stretchdelay 1.2s infinite ease-in-out; | |||||
| } | |||||
| #loadingPage .rect2 { | |||||
| -webkit-animation-delay: -1.1s; | |||||
| animation-delay: -1.1s; | |||||
| } | |||||
| #loadingPage .rect3 { | |||||
| -webkit-animation-delay: -1.0s; | |||||
| animation-delay: -1.0s; | |||||
| } | |||||
| #loadingPage .rect4 { | |||||
| -webkit-animation-delay: -0.9s; | |||||
| animation-delay: -0.9s; | |||||
| } | |||||
| #loadingPage .rect5 { | |||||
| -webkit-animation-delay: -0.8s; | |||||
| animation-delay: -0.8s; | |||||
| } | |||||
| .left2{ | |||||
| margin-left: -2px; | |||||
| } | |||||
| @-webkit-keyframes sk-stretchdelay { | |||||
| 0%, | |||||
| 40%, | |||||
| 100% { | |||||
| -webkit-transform: scaleY(0.4) | |||||
| } | |||||
| 20% { | |||||
| -webkit-transform: scaleY(1.0) | |||||
| } | |||||
| } | |||||
| @keyframes sk-stretchdelay { | |||||
| 0%, | |||||
| 40%, | |||||
| 100% { | |||||
| transform: scaleY(0.4); | |||||
| -webkit-transform: scaleY(0.4); | |||||
| } | |||||
| 20% { | |||||
| transform: scaleY(1.0); | |||||
| -webkit-transform: scaleY(1.0); | |||||
| } | |||||
| } | |||||
| </style> | |||||
| <!-- <div class="ui page dimmer"> | |||||
| <div class="ui text loader">{{.i18n.Tr "loading"}}</div> | |||||
| </div> --> | |||||
| <div id="mask"> | |||||
| <div id="loadingPage"> | |||||
| <div class="rect1"></div> | |||||
| <div class="rect2"></div> | |||||
| <div class="rect3"></div> | |||||
| <div class="rect4"></div> | |||||
| <div class="rect5"></div> | |||||
| </div> | |||||
| </div> | |||||
| <div class="repository"> | |||||
| {{template "repo/header" .}} | |||||
| <div class="ui container"> | |||||
| {{template "base/alert" .}} | |||||
| <h4 class="ui top attached header"> | |||||
| {{.i18n.Tr "repo.modelarts.train_job.new"}} | |||||
| </h4> | |||||
| <div class="ui attached segment"> | |||||
| <!-- equal width --> | |||||
| <form class="ui form" action="{{$.RepoLink}}/modelarts/train-job/{{.JobID}}/create_version" method="post"> | |||||
| {{.CsrfTokenHtml}} | |||||
| <input type="hidden" name="action" value="update"> | |||||
| <input type="hidden" name="version_name" value=""> | |||||
| <input type="hidden" id="ai_engine_name" name="engine_names" value=""> | |||||
| <input type="hidden" id="ai_flaver_name" name="flaver_names" value=""> | |||||
| <h4 class="unite title ui header ">{{.i18n.Tr "repo.modelarts.train_job.basic_info"}}:</h4> | |||||
| <div class="required unite min_title inline field"> | |||||
| <label>{{.i18n.Tr "repo.modelarts.train_job.job_name"}}</label> | |||||
| <input type="hidden" style="width: 60%;" name="job_name" id="trainjob_job_name" value="{{.job_name}}"> | |||||
| <input style="width: 60%;" value="{{.job_name}}" tabindex="3" disabled > | |||||
| </div> | |||||
| <div class="required unite min_title inline field"> | |||||
| <label>{{.i18n.Tr "repo.modelarts.parents_version"}}</label> | |||||
| <input id="parents_version" style="width: 60%;" value="" tabindex="3" disabled > | |||||
| </div> | |||||
| <div class="unite min_title inline field"> | |||||
| <label for="description">{{.i18n.Tr "repo.modelarts.train_job.description"}} </label> | |||||
| <textarea style="width: 80%;" id="description" value="{{.description}}" name="description" rows="3" maxlength="255" placeholder={{.i18n.Tr "repo.modelarts.train_job.new_place"}} onchange="this.value=this.value.substring(0, 255)" onkeydown="this.value=this.value.substring(0, 255)" onkeyup="this.value=this.value.substring(0, 256)">{{.description}}</textarea> | |||||
| </div> | |||||
| <div class="ui divider"></div> | |||||
| <h4 class="unite title ui header ">{{.i18n.Tr "repo.modelarts.train_job.parameter_setting"}}:</h4> | |||||
| <div class="required unite min_title inline field"> | |||||
| <label>{{.i18n.Tr "repo.modelarts.code_version"}}</label> | |||||
| <select class="ui dropdown width80 left2" id="code_version" name="branch_name"> | |||||
| {{if .branch_name}} | |||||
| <option name="branch_name" value="{{.branch_name}}">{{.branch_name}}</option> | |||||
| {{end}} | |||||
| {{range $k, $v :=.branches}} | |||||
| {{if ne $.branch_name $v}} | |||||
| <option name="branch_name" value="{{$v}}">{{$v}}</option> | |||||
| {{end}} | |||||
| {{end}} | |||||
| </select> | |||||
| </div> | |||||
| <div class="required unite min_title inline fields" style="width: 90%;"> | |||||
| <label>{{.i18n.Tr "repo.modelarts.train_job.AI_driver"}} </label> | |||||
| <div class="field" style="flex: 1.5;"> | |||||
| <select class="ui dropdown width" id="trainjob_engines" > | |||||
| {{range .engines}} | |||||
| <option value="{{.Value}}">{{.Value}}</option> | |||||
| {{end}} | |||||
| </select> | |||||
| </div> | |||||
| <div class="field" style="flex: 2;" id="engine_name"> | |||||
| <select class="ui dropdown width" id="trainjob_engine_versions" style='width: 100%;' name="engine_id"> | |||||
| {{if .engine_id}} | |||||
| <option name="engine_id" value="{{.engine_id}}">{{.engine_name}}</option> | |||||
| {{end}} | |||||
| {{range .engine_versions}} | |||||
| {{if ne $.engine_id .ID}} | |||||
| <option name="engine_id" value="{{.ID}}">{{.Value}}</option> | |||||
| {{end}} | |||||
| {{end}} | |||||
| </select> | |||||
| </div> | |||||
| </div> | |||||
| <div class="inline unite min_title field required"> | |||||
| <label>{{.i18n.Tr "repo.modelarts.train_job.start_file"}}</label> | |||||
| {{if .boot_file}} | |||||
| <input style="width: 33.5%;" name="boot_file" id="trainjob_boot_file" value="{{.boot_file}}" tabindex="3" autofocus required maxlength="255" > | |||||
| {{else}} | |||||
| <input style="width: 33.5%;" name="boot_file" id="trainjob_boot_file" value="" tabindex="3" autofocus required maxlength="255" > | |||||
| {{end}} | |||||
| <span> | |||||
| <i class="question circle icon link" data-content={{.i18n.Tr "repo.modelarts.train_job.boot_file_helper"}} data-position="right center" data-variation="mini"></i> | |||||
| </span> | |||||
| </div> | |||||
| <div class="required unite min_title inline field"> | |||||
| <label>{{.i18n.Tr "repo.modelarts.train_job.dataset"}}</label> | |||||
| <select class="ui dropdown width80" id="trainjob_datasets" name="attachment" placeholder="选择数据集"> | |||||
| {{if .dataset_name}} | |||||
| <option name="attachment" value="{{.uuid}}">{{.dataset_name}}</option> | |||||
| {{end}} | |||||
| {{range .attachments}} | |||||
| <option value="">选择数据集</option> | |||||
| {{if ne $.uuid .UUID}} | |||||
| <option name="attachment" value="{{.UUID}}">{{.Attachment.Name}}</option> | |||||
| {{end}} | |||||
| {{end}} | |||||
| </select> | |||||
| </div> | |||||
| <div class="inline unite min_title field"> | |||||
| <label>{{.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> | |||||
| <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> | |||||
| </div> | |||||
| <div class="required field " style="display: none;"> | |||||
| <label>{{.i18n.Tr "repo.modelarts.train_job.resource_pool"}}</label> | |||||
| <select class="ui dropdown" id="trainjob_resource_pool" style='width:385px' name="pool_id"> | |||||
| {{range .resource_pools}} | |||||
| <option value="{{.ID}}">{{.Value}}</option> | |||||
| {{end}} | |||||
| </select> | |||||
| </div> | |||||
| <div class="required grouped fields" style="display: none;"> | |||||
| <label for="resource_type">{{.i18n.Tr "repo.modelarts.train_job.resource_type"}}</label> | |||||
| <div class="field"> | |||||
| <div class="ui grid"> | |||||
| <div class="column"> | |||||
| <div class="ui radio checkbox"> | |||||
| <input type="radio" name="resource_type" checked="" tabindex="0"> | |||||
| </div> | |||||
| </div> | |||||
| <div class="three wide column">train-private-1</div> | |||||
| <div class="three wide column">{{svg "octicon-verified" 16}} 运行中</div> | |||||
| <div class="three wide column"> CPU:192 核 2048GiB</div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div class="required unite min_title inline field" id="flaver_name"> | |||||
| <label>{{.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="inline required unite min_title field"> | |||||
| <label>{{.i18n.Tr "repo.modelarts.train_job.amount_of_compute_node"}}</label> | |||||
| <div class="ui labeled input" style="width: 5%;"> | |||||
| <input style="border-radius: 0;text-align: center;" name="work_server_number" id="trainjob_work_server_num" tabindex="3" autofocus required maxlength="255" value="{{.work_server_number}}" readonly> | |||||
| </div> | |||||
| </div> | |||||
| <div class="inline unite min_title field"> | |||||
| <button class="ui create_train_job green button"> | |||||
| {{.i18n.Tr "repo.cloudbrain.new"}} | |||||
| </button> | |||||
| <a class="ui button" href="/">{{.i18n.Tr "repo.cloudbrain.cancel"}}</a> | |||||
| </div> | |||||
| <!-- 模态框 --> | |||||
| </form> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| {{template "base/footer" .}} | |||||
| <script> | |||||
| let url_href = {{.RepoLink}}+'/modelarts/train-job' | |||||
| let url_post = location.pathname | |||||
| let version_name = location.search.split('?version_name=')[1] | |||||
| $("#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) | |||||
| $('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){ | |||||
| value = '<div class="two fields width85" id= "para'+ i +'">' + | |||||
| '<div class="field">' + | |||||
| '<input type="text" name="shipping_first-name" required placeholder={{.i18n.Tr "repo.modelarts.train_job.parameter_name"}}> ' + | |||||
| '</div> ' + | |||||
| '<div class="field"> ' + | |||||
| '<input type="text" name="shipping_last-name" required placeholder={{.i18n.Tr "repo.modelarts.train_job.parameter_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(); | |||||
| $('.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个字符。' | |||||
| } | |||||
| ] | |||||
| }, | |||||
| attachment:{ | |||||
| identifier : 'attachment', | |||||
| rules: [ | |||||
| { | |||||
| type: 'empty', | |||||
| prompt : '选择一个数据集' | |||||
| } | |||||
| ] | |||||
| }, | |||||
| work_server_number: { | |||||
| identifier : 'work_server_number', | |||||
| rules: [ | |||||
| { | |||||
| type : 'integer[1..25]', | |||||
| prompt : '计算节点需要在1-25之间,请您键入正确的值' | |||||
| } | |||||
| ] | |||||
| }, | |||||
| run_para_list:{ | |||||
| identifier : 'run_para_list', | |||||
| rules: [ | |||||
| { | |||||
| type: 'maxLength[256]', | |||||
| prompt : '所有字符最长不超过256个字符。' | |||||
| } | |||||
| ] | |||||
| }, | |||||
| }, | |||||
| }) | |||||
| 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个字符。' | |||||
| } | |||||
| ] | |||||
| }, | |||||
| attachment:{ | |||||
| identifier : 'attachment', | |||||
| rules: [ | |||||
| { | |||||
| type: 'empty', | |||||
| prompt : '选择一个数据集' | |||||
| } | |||||
| ] | |||||
| }, | |||||
| work_server_number: { | |||||
| identifier : 'work_server_number', | |||||
| rules: [ | |||||
| { | |||||
| type : 'integer[1..25]', | |||||
| prompt : '计算节点需要在1-25之间,请您键入正确的值' | |||||
| } | |||||
| ] | |||||
| }, | |||||
| run_para_list:{ | |||||
| identifier : 'run_para_list', | |||||
| rules: [ | |||||
| { | |||||
| type: 'maxLength[256]', | |||||
| prompt : '所有字符最长不超过256个字符。' | |||||
| } | |||||
| ] | |||||
| }, | |||||
| }, | |||||
| onSuccess: function(){ | |||||
| // $('.ui.page.dimmer').dimmer('show') | |||||
| document.getElementById("mask").style.display = "block" | |||||
| }, | |||||
| onFailure: function(e){ | |||||
| 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() | |||||
| console.log(name1,name2) | |||||
| $("input#ai_engine_name").val(name1) | |||||
| $("input#ai_flaver_name").val(name2) | |||||
| } | |||||
| $('.ui.create_train_job.green.button').click(function(e) { | |||||
| get_name() | |||||
| send_run_para() | |||||
| validate() | |||||
| }) | |||||
| </script> | |||||
| @@ -2785,67 +2785,6 @@ $(document).ready(async () => { | |||||
| } | } | ||||
| }); | }); | ||||
| } | } | ||||
| // dataset Dropzone | |||||
| // const $dataset = $('#dataset'); | |||||
| // if ($dataset.length > 0) { | |||||
| // const filenameDict = {}; | |||||
| // let previewTemplate = ''; | |||||
| // previewTemplate += '<div class="dz-preview dz-file-preview">\n '; | |||||
| // previewTemplate += ' <div class="dz-details">\n '; | |||||
| // previewTemplate += ' <div class="dz-filename">'; | |||||
| // previewTemplate += ' <span data-dz-name data-dz-thumbnail></span>'; | |||||
| // previewTemplate += ' </div>\n '; | |||||
| // previewTemplate += ' <div class="dz-size" data-dz-size></div>\n '; | |||||
| // previewTemplate += ' </div>\n '; | |||||
| // previewTemplate += ' <div class="dz-progress ui active progress">'; | |||||
| // previewTemplate += ' <div class="dz-upload bar" data-dz-uploadprogress><div class="progress"></div></div>\n '; | |||||
| // previewTemplate += ' </div>\n '; | |||||
| // previewTemplate += ' <div class="dz-success-mark">'; | |||||
| // previewTemplate += ' <span>上传成功</span>'; | |||||
| // previewTemplate += ' </div>\n '; | |||||
| // previewTemplate += ' <div class="dz-error-mark">'; | |||||
| // previewTemplate += ' <span>上传失败</span>'; | |||||
| // previewTemplate += ' </div>\n '; | |||||
| // previewTemplate += ' <div class="dz-error-message">'; | |||||
| // previewTemplate += ' <span data-dz-errormessage></span>'; | |||||
| // previewTemplate += ' </div>\n'; | |||||
| // previewTemplate += '</div>'; | |||||
| // await createDropzone('#dataset', { | |||||
| // url: $dataset.data('upload-url'), | |||||
| // headers: {'X-Csrf-Token': csrf}, | |||||
| // maxFiles: $dataset.data('max-file'), | |||||
| // maxFilesize: $dataset.data('max-size'), | |||||
| // acceptedFiles: ($dataset.data('accepts') === '*/*') ? null : $dataset.data('accepts'), | |||||
| // addRemoveLinks: true, | |||||
| // timeout: 0, | |||||
| // dictDefaultMessage: $dataset.data('default-message'), | |||||
| // dictInvalidFileType: $dataset.data('invalid-input-type'), | |||||
| // dictFileTooBig: $dataset.data('file-too-big'), | |||||
| // dictRemoveFile: $dataset.data('remove-file'), | |||||
| // previewTemplate, | |||||
| // init() { | |||||
| // this.on('success', (file, data) => { | |||||
| // filenameDict[file.name] = data.uuid; | |||||
| // const input = $(`<input id="${data.uuid}" name="files" type="hidden">`).val(data.uuid); | |||||
| // $('.files').append(input); | |||||
| // }); | |||||
| // this.on('removedfile', (file) => { | |||||
| // if (file.name in filenameDict) { | |||||
| // $(`#${filenameDict[file.name]}`).remove(); | |||||
| // } | |||||
| // if ($dataset.data('remove-url') && $dataset.data('csrf')) { | |||||
| // $.post($dataset.data('remove-url'), { | |||||
| // file: filenameDict[file.name], | |||||
| // _csrf: $dataset.data('csrf') | |||||
| // }); | |||||
| // } | |||||
| // }); | |||||
| // }, | |||||
| // }); | |||||
| // } | |||||
| // Helpers. | // Helpers. | ||||
| $('.delete-button').on('click', showDeletePopup); | $('.delete-button').on('click', showDeletePopup); | ||||
| $('.add-all-button').on('click', showAddAllPopup); | $('.add-all-button').on('click', showAddAllPopup); | ||||
| @@ -3984,243 +3923,6 @@ function initNavbarContentToggle() { | |||||
| }); | }); | ||||
| } | } | ||||
| // function initTopicbar() { | |||||
| // const mgrBtn = $('#manage_topic'); | |||||
| // const editDiv = $('#topic_edit'); | |||||
| // const viewDiv = $('#repo-topics'); | |||||
| // const saveBtn = $('#save_topic'); | |||||
| // const topicDropdown = $('#topic_edit .dropdown'); | |||||
| // const topicForm = $('#topic_edit.ui.form'); | |||||
| // const topicInput = $("#topics_input") | |||||
| // const topicPrompts = getPrompts(); | |||||
| // mgrBtn.on('click', (e) => { | |||||
| // // viewDiv.hide(); | |||||
| // editDiv.css('display', ''); // show Semantic UI Grid | |||||
| // topicInput.val('') | |||||
| // console.log("-----------------asdasd",$("#topics_input"),$("#topics_input").val()) | |||||
| // stopPropagation(e); | |||||
| // }); | |||||
| // $(document).bind('click',function(){ | |||||
| // editDiv.css('display','none'); | |||||
| // }) | |||||
| // editDiv.click(function(e){ | |||||
| // stopPropagation(e); | |||||
| // }) | |||||
| // function getPrompts() { | |||||
| // const hidePrompt = $('div.hide#validate_prompt'); | |||||
| // const prompts = { | |||||
| // countPrompt: hidePrompt.children('#count_prompt').text(), | |||||
| // formatPrompt: hidePrompt.children('#format_prompt').text() | |||||
| // }; | |||||
| // hidePrompt.remove(); | |||||
| // return prompts; | |||||
| // } | |||||
| // function stopPropagation(e) { | |||||
| // var ev = e || window.event; | |||||
| // if (ev.stopPropagation) { | |||||
| // ev.stopPropagation(); | |||||
| // } | |||||
| // else if (window.event) { | |||||
| // window.event.cancelBubble = true;//兼容IE | |||||
| // } | |||||
| // } | |||||
| // saveBtn.on('click', () => { | |||||
| // const topics = $('input[name=topics]').val(); | |||||
| // $.post( | |||||
| // saveBtn.data('link'), | |||||
| // { | |||||
| // _csrf: csrf, | |||||
| // topics | |||||
| // }, | |||||
| // (_data, _textStatus, xhr) => { | |||||
| // if (xhr.responseJSON.status === 'ok') { | |||||
| // console.log("--------saveBtn------------") | |||||
| // viewDiv.children('.topic').remove(); | |||||
| // if (topics.length) { | |||||
| // const topicArray = topics.split(','); | |||||
| // const last = viewDiv.children('a').last(); | |||||
| // for (let i = 0; i < topicArray.length; i++) { | |||||
| // const link = $('<a class="ui repo-topic small label topic"></a>'); | |||||
| // link.attr( | |||||
| // 'href', | |||||
| // `${AppSubUrl}/explore/repos?q=${encodeURIComponent( | |||||
| // topicArray[i] | |||||
| // )}&topic=1` | |||||
| // ); | |||||
| // link.text(topicArray[i]); | |||||
| // link.insertBefore(last); | |||||
| // } | |||||
| // } | |||||
| // editDiv.css('display', 'none'); | |||||
| // viewDiv.show(); | |||||
| // } | |||||
| // } | |||||
| // ) | |||||
| // .fail((xhr) => { | |||||
| // if (xhr.status === 422) { | |||||
| // if (xhr.responseJSON.invalidTopics.length > 0) { | |||||
| // topicPrompts.formatPrompt = xhr.responseJSON.message; | |||||
| // const {invalidTopics} = xhr.responseJSON; | |||||
| // const topicLables = topicDropdown.children('a.ui.label'); | |||||
| // topics.split(',').forEach((value, index) => { | |||||
| // for (let i = 0; i < invalidTopics.length; i++) { | |||||
| // if (invalidTopics[i] === value) { | |||||
| // topicLables | |||||
| // .eq(index) | |||||
| // .removeClass('green') | |||||
| // .addClass('red'); | |||||
| // } | |||||
| // } | |||||
| // }); | |||||
| // } else { | |||||
| // topicPrompts.countPrompt = xhr.responseJSON.message; | |||||
| // } | |||||
| // } | |||||
| // }) | |||||
| // .always(() => { | |||||
| // topicForm.form('validate form'); | |||||
| // }); | |||||
| // }); | |||||
| // topicDropdown.dropdown({ | |||||
| // allowAdditions: true, | |||||
| // forceSelection: false, | |||||
| // fields: {name: 'description', value: 'data-value'}, | |||||
| // saveRemoteData: false, | |||||
| // label: { | |||||
| // transition: 'horizontal flip', | |||||
| // duration: 200, | |||||
| // variation: false, | |||||
| // blue: true, | |||||
| // basic: true | |||||
| // }, | |||||
| // className: { | |||||
| // label: 'ui small label' | |||||
| // }, | |||||
| // apiSettings: { | |||||
| // url: `${AppSubUrl}/api/v1/topics/search?q={query}`, | |||||
| // throttle: 500, | |||||
| // cache: false, | |||||
| // onResponse(res) { | |||||
| // const formattedResponse = { | |||||
| // success: false, | |||||
| // results: [] | |||||
| // }; | |||||
| // const stripTags = function (text) { | |||||
| // return text.replace(/<[^>]*>?/gm, ''); | |||||
| // }; | |||||
| // const query = stripTags(this.urlData.query.trim()); | |||||
| // let found_query = false; | |||||
| // const current_topics = []; | |||||
| // topicDropdown | |||||
| // .find('div.label.visible.topic,a.label.visible') | |||||
| // .each((_, e) => { | |||||
| // current_topics.push(e.dataset.value); | |||||
| // }); | |||||
| // if (res.topics) { | |||||
| // let found = false; | |||||
| // for (let i = 0; i < res.topics.length; i++) { | |||||
| // // skip currently added tags | |||||
| // if (current_topics.includes(res.topics[i].topic_name)) { | |||||
| // continue; | |||||
| // } | |||||
| // if ( | |||||
| // res.topics[i].topic_name.toLowerCase() === query.toLowerCase() | |||||
| // ) { | |||||
| // found_query = true; | |||||
| // } | |||||
| // formattedResponse.results.push({ | |||||
| // description: res.topics[i].topic_name, | |||||
| // 'data-value': res.topics[i].topic_name | |||||
| // }); | |||||
| // found = true; | |||||
| // } | |||||
| // formattedResponse.success = found; | |||||
| // } | |||||
| // if (query.length > 0 && !found_query) { | |||||
| // formattedResponse.success = true; | |||||
| // formattedResponse.results.unshift({ | |||||
| // description: query, | |||||
| // 'data-value': query | |||||
| // }); | |||||
| // } else if (query.length > 0 && found_query) { | |||||
| // formattedResponse.results.sort((a, b) => { | |||||
| // if (a.description.toLowerCase() === query.toLowerCase()) return -1; | |||||
| // if (b.description.toLowerCase() === query.toLowerCase()) return 1; | |||||
| // if (a.description > b.description) return -1; | |||||
| // if (a.description < b.description) return 1; | |||||
| // return 0; | |||||
| // }); | |||||
| // } | |||||
| // return formattedResponse; | |||||
| // } | |||||
| // }, | |||||
| // onLabelCreate(value) { | |||||
| // value = value.toLowerCase().trim(); | |||||
| // this.attr('data-value', value) | |||||
| // .contents() | |||||
| // .first() | |||||
| // .replaceWith(value); | |||||
| // return $(this); | |||||
| // }, | |||||
| // onAdd(addedValue, _addedText, $addedChoice) { | |||||
| // addedValue = addedValue.toLowerCase().trim(); | |||||
| // $($addedChoice).attr('data-value', addedValue); | |||||
| // $($addedChoice).attr('data-text', addedValue); | |||||
| // } | |||||
| // }); | |||||
| // $.fn.form.settings.rules.validateTopic = function (_values, regExp) { | |||||
| // const topics = topicDropdown.children('a.ui.label'); | |||||
| // const status = | |||||
| // topics.length === 0 || (topics.last().attr('data-value').match(regExp) !== null && topics.last().attr('data-value').length <= 35); | |||||
| // if (!status) { | |||||
| // topics | |||||
| // .last() | |||||
| // .removeClass('green') | |||||
| // .addClass('red'); | |||||
| // } | |||||
| // return status && topicDropdown.children('a.ui.label.red').length === 0; | |||||
| // }; | |||||
| // topicForm.form({ | |||||
| // on: 'change', | |||||
| // inline: true, | |||||
| // fields: { | |||||
| // topics: { | |||||
| // identifier: 'topics', | |||||
| // rules: [ | |||||
| // { | |||||
| // type: 'validateTopic', | |||||
| // value: /^[\u4e00-\u9fa5a-z0-9][\u4e00-\u9fa5a-z0-9-]{0,105}$/, | |||||
| // prompt: topicPrompts.formatPrompt | |||||
| // }, | |||||
| // { | |||||
| // type: 'maxCount[25]', | |||||
| // prompt: topicPrompts.countPrompt | |||||
| // } | |||||
| // ] | |||||
| // } | |||||
| // } | |||||
| // }); | |||||
| // } | |||||
| window.toggleDeadlineForm = function () { | window.toggleDeadlineForm = function () { | ||||
| $('#deadlineForm').fadeToggle(150); | $('#deadlineForm').fadeToggle(150); | ||||