| @@ -36,6 +36,7 @@ type AiModelManage struct { | |||
| CreatedUnix timeutil.TimeStamp `xorm:"created"` | |||
| UpdatedUnix timeutil.TimeStamp `xorm:"updated"` | |||
| IsCanOper bool | |||
| IsCanDelete bool | |||
| } | |||
| type AiModelQueryOptions struct { | |||
| @@ -33,6 +33,7 @@ const ( | |||
| JobTypeSnn4imagenet JobType = "SNN4IMAGENET" | |||
| JobTypeBrainScore JobType = "BRAINSCORE" | |||
| JobTypeTrain JobType = "TRAIN" | |||
| JobTypeInference JobType = "INFERENCE" | |||
| //notebook | |||
| ModelArtsCreateQueue ModelArtsJobStatus = "CREATE_QUEUING" //免费资源创建排队中 | |||
| @@ -113,7 +114,7 @@ type Cloudbrain struct { | |||
| ComputeResource string //计算资源,例如npu | |||
| EngineID int64 //引擎id | |||
| TrainUrl string //输出的obs路径 | |||
| TrainUrl string //输出模型的obs路径 | |||
| BranchName string //分支名称 | |||
| Parameters string //传给modelarts的param参数 | |||
| BootFile string //启动文件 | |||
| @@ -127,6 +128,12 @@ type Cloudbrain struct { | |||
| EngineName string //引擎名称 | |||
| TotalVersionCount int //任务的所有版本数量,包括删除的 | |||
| LabelName string //标签名称 | |||
| ModelName string //模型名称 | |||
| ModelVersion string //模型版本 | |||
| CkptName string //权重文件名称 | |||
| ResultUrl string //推理结果的obs路径 | |||
| User *User `xorm:"-"` | |||
| Repo *Repository `xorm:"-"` | |||
| } | |||
| @@ -699,6 +706,25 @@ type Config struct { | |||
| Flavor Flavor `json:"flavor"` | |||
| PoolID string `json:"pool_id"` | |||
| } | |||
| type CreateInferenceJobParams struct { | |||
| JobName string `json:"job_name"` | |||
| Description string `json:"job_desc"` | |||
| InfConfig InfConfig `json:"config"` | |||
| WorkspaceID string `json:"workspace_id"` | |||
| } | |||
| type InfConfig 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"` | |||
| LogUrl string `json:"log_url"` | |||
| CreateVersion bool `json:"create_version"` | |||
| Flavor Flavor `json:"flavor"` | |||
| PoolID string `json:"pool_id"` | |||
| } | |||
| type CreateTrainJobVersionParams struct { | |||
| Description string `json:"job_desc"` | |||
| @@ -1033,6 +1059,7 @@ func QueryModelTrainJobList(repoId int64) ([]*CloudbrainInfo, int, error) { | |||
| cond = cond.And( | |||
| builder.Eq{"job_type": "TRAIN"}, | |||
| ) | |||
| cloudbrains := make([]*CloudbrainInfo, 0) | |||
| if err := sess.Select("job_id,job_name").Table(&Cloudbrain{}).Where(cond).OrderBy("created_unix DESC"). | |||
| Find(&cloudbrains); err != nil { | |||
| @@ -1266,6 +1293,22 @@ func GetCloudbrainTrainJobCountByUserID(userID int64) (int, error) { | |||
| return int(count), err | |||
| } | |||
| func GetCloudbrainInferenceJobCountByUserID(userID int64) (int, error) { | |||
| count, err := x.In("status", ModelArtsTrainJobInit, ModelArtsTrainJobImageCreating, ModelArtsTrainJobSubmitTrying, ModelArtsTrainJobWaiting, ModelArtsTrainJobRunning, ModelArtsTrainJobScaling, ModelArtsTrainJobCheckInit, ModelArtsTrainJobCheckRunning, ModelArtsTrainJobCheckRunningCompleted). | |||
| And("job_type = ? and user_id = ? and type = ?", JobTypeInference, userID, TypeCloudBrainTwo).Count(new(Cloudbrain)) | |||
| return int(count), err | |||
| } | |||
| func UpdateInferenceJob(job *Cloudbrain) error { | |||
| return updateInferenceJob(x, job) | |||
| } | |||
| func updateInferenceJob(e Engine, job *Cloudbrain) error { | |||
| var sess *xorm.Session | |||
| sess = e.Where("job_id = ?", job.JobID) | |||
| _, err := sess.Cols("status", "train_job_duration").Update(job) | |||
| return err | |||
| } | |||
| func RestartCloudbrain(old *Cloudbrain, new *Cloudbrain) (err error) { | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| @@ -305,7 +305,10 @@ func NotifyWatchersActions(acts []*Action) error { | |||
| return err | |||
| } | |||
| } | |||
| return sess.Commit() | |||
| err := sess.Commit() | |||
| producer(acts...) | |||
| return err | |||
| } | |||
| func watchIfAuto(e Engine, userID, repoID int64, isWrite bool) error { | |||
| @@ -45,6 +45,30 @@ type CreateModelArtsTrainJobForm struct { | |||
| EngineName string `form:"engine_names" binding:"Required"` | |||
| } | |||
| type CreateModelArtsInferenceJobForm struct { | |||
| JobName string `form:"job_name" binding:"Required"` | |||
| Attachment string `form:"attachment" binding:"Required"` | |||
| BootFile string `form:"boot_file" binding:"Required"` | |||
| WorkServerNumber int `form:"work_server_number" binding:"Required"` | |||
| EngineID int `form:"engine_id" binding:"Required"` | |||
| PoolID string `form:"pool_id" binding:"Required"` | |||
| Flavor string `form:"flavor" binding:"Required"` | |||
| Params string `form:"run_para_list" binding:"Required"` | |||
| Description string `form:"description"` | |||
| IsSaveParam string `form:"is_save_para"` | |||
| ParameterTemplateName string `form:"parameter_template_name"` | |||
| 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"` | |||
| LabelName string `form:"label_names" binding:"Required"` | |||
| TrainUrl string `form:"train_url" binding:"Required"` | |||
| ModelName string `form:"model_name" binding:"Required"` | |||
| ModelVersion string `form:"model_version" binding:"Required"` | |||
| CkptName string `form:"ckpt_name" binding:"Required"` | |||
| } | |||
| func (f *CreateModelArtsTrainJobForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { | |||
| return validate(errs, ctx.Data, f, ctx.Locale) | |||
| } | |||
| @@ -38,6 +38,7 @@ const ( | |||
| // "]}" | |||
| CodePath = "/code/" | |||
| OutputPath = "/output/" | |||
| ResultPath = "/result/" | |||
| LogPath = "/log/" | |||
| JobPath = "/job/" | |||
| OrderDesc = "desc" //向下查询 | |||
| @@ -45,6 +46,8 @@ const ( | |||
| Lines = 500 | |||
| TrainUrl = "train_url" | |||
| DataUrl = "data_url" | |||
| ResultUrl = "result_url" | |||
| CkptUrl = "ckpt_url" | |||
| PerPage = 10 | |||
| IsLatestVersion = "1" | |||
| NotLatestVersion = "0" | |||
| @@ -113,6 +116,36 @@ type GenerateTrainJobVersionReq struct { | |||
| TotalVersionCount int | |||
| } | |||
| type GenerateInferenceJobReq 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 | |||
| CommitID string | |||
| Params string | |||
| BranchName string | |||
| FlavorName string | |||
| EngineName string | |||
| LabelName string | |||
| IsLatestVersion string | |||
| VersionCount int | |||
| TotalVersionCount int | |||
| ModelName string | |||
| ModelVersion string | |||
| CkptName string | |||
| ResultUrl string | |||
| } | |||
| type VersionInfo struct { | |||
| Version []struct { | |||
| ID int `json:"id"` | |||
| @@ -333,10 +366,10 @@ func GenerateTrainJobVersion(ctx *context.Context, req *GenerateTrainJobReq, job | |||
| jobTypes = append(jobTypes, string(models.JobTypeTrain)) | |||
| repo := ctx.Repo.Repository | |||
| VersionTaskList, VersionListCount, err := models.CloudbrainsVersionList(&models.CloudbrainsOptions{ | |||
| RepoID: repo.ID, | |||
| Type: models.TypeCloudBrainTwo, | |||
| RepoID: repo.ID, | |||
| Type: models.TypeCloudBrainTwo, | |||
| JobTypes: jobTypes, | |||
| JobID: strconv.FormatInt(jobResult.JobID, 10), | |||
| JobID: strconv.FormatInt(jobResult.JobID, 10), | |||
| }) | |||
| if err != nil { | |||
| ctx.ServerError("Cloudbrain", err) | |||
| @@ -443,8 +476,82 @@ func TransTrainJobStatus(status int) string { | |||
| } | |||
| } | |||
| func GetVersionOutputPathByTotalVersionCount(TotalVersionCount int) (VersionOutputPath string) { | |||
| func GetOutputPathByCount(TotalVersionCount int) (VersionOutputPath string) { | |||
| talVersionCountToString := fmt.Sprintf("%04d", TotalVersionCount) | |||
| VersionOutputPath = "V" + talVersionCountToString | |||
| return VersionOutputPath | |||
| } | |||
| func GenerateInferenceJob(ctx *context.Context, req *GenerateInferenceJobReq) (err error) { | |||
| jobResult, err := createInferenceJob(models.CreateInferenceJobParams{ | |||
| JobName: req.JobName, | |||
| Description: req.Description, | |||
| InfConfig: models.InfConfig{ | |||
| WorkServerNum: req.WorkServerNumber, | |||
| AppUrl: req.CodeObsPath, | |||
| BootFileUrl: req.BootFileUrl, | |||
| DataUrl: req.DataUrl, | |||
| EngineID: req.EngineID, | |||
| // TrainUrl: req.TrainUrl, | |||
| LogUrl: req.LogUrl, | |||
| PoolID: req.PoolID, | |||
| CreateVersion: true, | |||
| Flavor: models.Flavor{ | |||
| Code: req.FlavorCode, | |||
| }, | |||
| Parameter: req.Parameters, | |||
| }, | |||
| }) | |||
| 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 | |||
| } | |||
| 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.JobTypeInference), | |||
| Type: models.TypeCloudBrainTwo, | |||
| VersionID: jobResult.VersionID, | |||
| VersionName: jobResult.VersionName, | |||
| Uuid: req.Uuid, | |||
| DatasetName: attach.Name, | |||
| CommitID: req.CommitID, | |||
| 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, | |||
| LabelName: req.LabelName, | |||
| IsLatestVersion: req.IsLatestVersion, | |||
| VersionCount: req.VersionCount, | |||
| TotalVersionCount: req.TotalVersionCount, | |||
| ModelName: req.ModelName, | |||
| ModelVersion: req.ModelVersion, | |||
| CkptName: req.CkptName, | |||
| ResultUrl: req.ResultUrl, | |||
| }) | |||
| if err != nil { | |||
| log.Error("CreateCloudbrain(%s) failed:%v", req.JobName, err.Error()) | |||
| return err | |||
| } | |||
| return nil | |||
| } | |||
| @@ -874,3 +874,59 @@ sendjob: | |||
| return &result, nil | |||
| } | |||
| func createInferenceJob(createJobParams models.CreateInferenceJobParams) (*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(createJobParams). | |||
| SetResult(&result). | |||
| Post(HOST + "/v1/" + setting.ProjectID + urlTrainJob) | |||
| if err != nil { | |||
| return nil, fmt.Errorf("resty create inference-job: %s", err) | |||
| } | |||
| req, _ := json.Marshal(createJobParams) | |||
| 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()) | |||
| } | |||
| log.Error("createInferenceJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||
| BootFileErrorMsg := "Invalid OBS path '" + createJobParams.InfConfig.BootFileUrl + "'." | |||
| DataSetErrorMsg := "Invalid OBS path '" + createJobParams.InfConfig.DataUrl + "'." | |||
| if temp.ErrorMsg == BootFileErrorMsg { | |||
| log.Error("启动文件错误!createInferenceJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||
| return &result, fmt.Errorf("启动文件错误!") | |||
| } | |||
| if temp.ErrorMsg == DataSetErrorMsg { | |||
| log.Error("数据集错误!createInferenceJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||
| return &result, fmt.Errorf("数据集错误!") | |||
| } | |||
| return &result, fmt.Errorf("createInferenceJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||
| } | |||
| if !result.IsSuccess { | |||
| log.Error("createInferenceJob failed(%s): %s", result.ErrorCode, result.ErrorMsg) | |||
| return &result, fmt.Errorf("createInferenceJob failed(%s): %s", result.ErrorCode, result.ErrorMsg) | |||
| } | |||
| return &result, nil | |||
| } | |||
| @@ -28,6 +28,13 @@ type FileInfo struct { | |||
| ParenDir string `json:"ParenDir"` | |||
| UUID string `json:"UUID"` | |||
| } | |||
| type FileInfoList []FileInfo | |||
| func (ulist FileInfoList) Swap(i, j int) { ulist[i], ulist[j] = ulist[j], ulist[i] } | |||
| func (ulist FileInfoList) Len() int { return len(ulist) } | |||
| func (ulist FileInfoList) Less(i, j int) bool { | |||
| return strings.Compare(ulist[i].FileName, ulist[j].FileName) > 0 | |||
| } | |||
| //check if has the object | |||
| func ObsHasObject(path string) (bool, error) { | |||
| @@ -333,7 +340,8 @@ func GetAllObjectByBucketAndPrefix(bucket string, prefix string) ([]FileInfo, er | |||
| input.MaxKeys = 100 | |||
| input.Prefix = prefix | |||
| index := 1 | |||
| fileInfos := make([]FileInfo, 0) | |||
| fileInfoList := FileInfoList{} | |||
| prefixLen := len(prefix) | |||
| log.Info("prefix=" + input.Prefix) | |||
| for { | |||
| @@ -358,7 +366,7 @@ func GetAllObjectByBucketAndPrefix(bucket string, prefix string) ([]FileInfo, er | |||
| IsDir: isDir, | |||
| ParenDir: "", | |||
| } | |||
| fileInfos = append(fileInfos, fileInfo) | |||
| fileInfoList = append(fileInfoList, fileInfo) | |||
| } | |||
| if output.IsTruncated { | |||
| input.Marker = output.NextMarker | |||
| @@ -373,13 +381,14 @@ func GetAllObjectByBucketAndPrefix(bucket string, prefix string) ([]FileInfo, er | |||
| return nil, err | |||
| } | |||
| } | |||
| return fileInfos, nil | |||
| sort.Sort(fileInfoList) | |||
| return fileInfoList, nil | |||
| } | |||
| func GetObsListObject(jobName, parentDir, versionName string) ([]FileInfo, error) { | |||
| func GetObsListObject(jobName, outPutPath, parentDir, versionName string) ([]FileInfo, error) { | |||
| input := &obs.ListObjectsInput{} | |||
| input.Bucket = setting.Bucket | |||
| input.Prefix = strings.TrimPrefix(path.Join(setting.TrainJobModelPath, jobName, setting.OutPutPath, versionName, parentDir), "/") | |||
| input.Prefix = strings.TrimPrefix(path.Join(setting.TrainJobModelPath, jobName, outPutPath, versionName, parentDir), "/") | |||
| strPrefix := strings.Split(input.Prefix, "/") | |||
| output, err := ObsCli.ListObjects(input) | |||
| fileInfos := make([]FileInfo, 0) | |||
| @@ -401,7 +410,7 @@ func GetObsListObject(jobName, parentDir, versionName string) ([]FileInfo, error | |||
| nextParentDir = parentDir + "/" + fileName | |||
| } | |||
| if fileName == strPrefix[len(strPrefix)-1] || (fileName+"/") == setting.OutPutPath { | |||
| if fileName == strPrefix[len(strPrefix)-1] || (fileName+"/") == outPutPath { | |||
| continue | |||
| } | |||
| } else { | |||
| @@ -630,7 +630,7 @@ oauth2_application_create_description = OAuth2 applications gives your third-par | |||
| oauth2_application_remove_description = Removing an OAuth2 application will prevent it to access authorized user accounts on this instance. Continue? | |||
| authorized_oauth2_applications = Authorized OAuth2 Applications | |||
| authorized_oauth2_applications_description = You've granted access to your personal openi account to these third party applications. Please revoke access for applications no longer needed. | |||
| authorized_oauth2_applications_description = You have granted access to your personal openi account to these third party applications. Please revoke access for applications no longer needed. | |||
| revoke_key = Revoke | |||
| revoke_oauth2_grant = Revoke Access | |||
| revoke_oauth2_grant_description = Revoking access for this third party application will prevent this application from accessing your data. Are you sure? | |||
| @@ -869,6 +869,7 @@ modelarts.notebook=Debug Task | |||
| modelarts.train_job=Train Task | |||
| modelarts.train_job.new_debug= New Debug Task | |||
| modelarts.train_job.new_train=New Train Task | |||
| modelarts.train_job.new_infer=New Inference Task | |||
| modelarts.train_job.config=Configuration information | |||
| modelarts.train_job.new=New train Task | |||
| modelarts.train_job.new_place=The description should not exceed 256 characters | |||
| @@ -882,6 +883,8 @@ modelarts.parent_version=Parent Version | |||
| modelarts.run_version=Run Version | |||
| modelarts.train_job.compute_node=Compute Node | |||
| modelarts.create_model = Create Model | |||
| modelarts.model_label=Model Label | |||
| modelarts.infer_dataset = Inference Dataset | |||
| modelarts.train_job.basic_info=Basic Info | |||
| @@ -936,6 +939,12 @@ cloudbrain.benchmark.evaluate_child_type=Child Type | |||
| cloudbrain.benchmark.evaluate_mirror=Mirror | |||
| cloudbrain.benchmark.evaluate_train=Train Script | |||
| cloudbrain.benchmark.evaluate_test=Test Script | |||
| modelarts.infer_job_model = Model | |||
| modelarts.infer_job_model_file = Model File | |||
| modelarts.infer_job = Inference Job | |||
| modelarts.infer_job.model_version = Model/Version | |||
| modelarts.infer_job.select_model = Select Model | |||
| modelarts.infer_job.tooltip = The model has been deleted and cannot be viewed. | |||
| model.manage.import_new_model=Import New Model | |||
| model.manage.create_error=Equal Name and Version has existed. | |||
| @@ -831,7 +831,7 @@ debug=调试 | |||
| debug_again=再次调试 | |||
| stop=停止 | |||
| delete=删除 | |||
| model_download=模型下载 | |||
| model_download=结果下载 | |||
| submit_image=提交镜像 | |||
| download=模型下载 | |||
| @@ -876,9 +876,10 @@ modelarts.notebook=调试任务 | |||
| modelarts.train_job=训练任务 | |||
| modelarts.train_job.new_debug=新建调试任务 | |||
| modelarts.train_job.new_train=新建训练任务 | |||
| modelarts.train_job.new_infer=新建推理任务 | |||
| modelarts.train_job.config=配置信息 | |||
| modelarts.train_job.new=新建训练任务 | |||
| modelarts.train_job.new_place=描述字数不超过256个字符 | |||
| modelarts.train_job.new_place=描述字数不超过255个字符 | |||
| modelarts.model_name=模型名称 | |||
| modelarts.model_size=模型大小 | |||
| modelarts.import_model=导入模型 | |||
| @@ -888,6 +889,8 @@ modelarts.current_version=当前版本 | |||
| modelarts.parent_version=父版本 | |||
| modelarts.run_version=运行版本 | |||
| modelarts.create_model=创建模型 | |||
| modelarts.model_label=模型标签 | |||
| modelarts.infer_dataset = 推理数据集 | |||
| @@ -929,7 +932,7 @@ modelarts.train_job.NAS_mount_path=NAS挂载路径 | |||
| modelarts.train_job.query_whether_save_parameter=保存作业参数 | |||
| modelarts.train_job.save_helper=保存当前作业的配置参数,后续您可以使用已保存的配置参数快速创建训练作业。 | |||
| modelarts.train_job.common_frame=常用框架 | |||
| modelarts.train_job.amount_of_compute_node=计算节点个数 | |||
| modelarts.train_job.amount_of_compute_node=计算节点数 | |||
| modelarts.train_job.job_parameter_name=任务参数名称 | |||
| modelarts.train_job.parameter_description=任务参数描述 | |||
| modelarts.log=日志 | |||
| @@ -947,6 +950,14 @@ cloudbrain.benchmark.evaluate_train=训练程序 | |||
| cloudbrain.benchmark.evaluate_test=测试程序 | |||
| modelarts.infer_job_model = 模型名称 | |||
| modelarts.infer_job_model_file = 模型文件 | |||
| modelarts.infer_job = 推理任务 | |||
| modelarts.infer_job.model_version = 模型/版本 | |||
| modelarts.infer_job.select_model = 选择模型 | |||
| modelarts.infer_job.boot_file_helper=启动文件是您程序执行的入口文件,必须是以.py结尾的文件。比如inference.py、main.py、example/inference.py、case/main.py。 | |||
| modelarts.infer_job.tooltip = 该模型已删除,无法查看。 | |||
| model.manage.import_new_model=导入新模型 | |||
| model.manage.create_error=相同的名称和版本的模型已经存在。 | |||
| model.manage.model_name = 模型名称 | |||
| @@ -239,7 +239,7 @@ var actionNameZH={ | |||
| "5":"推送了 {branch} 分支的代码到", | |||
| "6":"创建了任务", | |||
| "7":"创建了合并请求", | |||
| "9":"推送了 {branch} 分支的代码到", | |||
| "9":"推送了标签 {branch} 到", | |||
| "10":"评论了任务", | |||
| "11":"合并了合并请求", | |||
| "12":"关闭了任务", | |||
| @@ -247,7 +247,7 @@ var actionNameZH={ | |||
| "14":"关闭了合并请求", | |||
| "15":"重新开启了合并请求", | |||
| "17":"从 {repoName} 删除分支 {deleteBranchName}", | |||
| "22":"拒绝了合并请求", | |||
| "22":"建议变更", | |||
| "23":"评论了合并请求" | |||
| }; | |||
| @@ -257,7 +257,7 @@ var actionNameEN={ | |||
| "5":" pushed to {branch} at", | |||
| "6":" opened issue", | |||
| "7":" created pull request", | |||
| "9":" pushed to {branch} at", | |||
| "9":" pushed tag {branch} to ", | |||
| "10":" commented on issue", | |||
| "11":" merged pull request", | |||
| "12":" closed issue", | |||
| @@ -265,7 +265,7 @@ var actionNameEN={ | |||
| "14":" closed pull request", | |||
| "15":" reopened pull request", | |||
| "17":" deleted branch {deleteBranchName} from {repoName}", | |||
| "22":" rejected pull request", | |||
| "22":" proposed changes", | |||
| "23":" commented on pull request" | |||
| }; | |||
| @@ -534,6 +534,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
| m.Get("/downloadAllOpenI", repo.ServeAllProjectsOpenIStatisticsFile) | |||
| m.Group("/project", func() { | |||
| m.Get("", repo.GetAllProjectsPeriodStatistics) | |||
| m.Get("/numVisit", repo.ProjectNumVisit) | |||
| m.Group("/:id", func() { | |||
| m.Get("", repo.GetProjectLatestStatistics) | |||
| @@ -893,6 +894,15 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
| m.Get("/model_list", repo.ModelList) | |||
| }) | |||
| }) | |||
| m.Group("/inference-job", func() { | |||
| m.Group("/:jobid", func() { | |||
| m.Get("", repo.GetModelArtsInferenceJob) | |||
| m.Get("/log", repo.TrainJobGetLog) | |||
| m.Post("/del_version", repo.DelTrainJobVersion) | |||
| m.Post("/stop_version", repo.StopTrainJobVersion) | |||
| m.Get("/result_list", repo.ResultList) | |||
| }) | |||
| }) | |||
| }, reqRepoReader(models.UnitTypeCloudBrain)) | |||
| }, repoAssignment()) | |||
| }) | |||
| @@ -6,11 +6,12 @@ | |||
| package repo | |||
| import ( | |||
| "code.gitea.io/gitea/modules/util" | |||
| "net/http" | |||
| "strconv" | |||
| "strings" | |||
| "code.gitea.io/gitea/modules/util" | |||
| "code.gitea.io/gitea/models" | |||
| "code.gitea.io/gitea/modules/context" | |||
| "code.gitea.io/gitea/modules/log" | |||
| @@ -133,7 +134,6 @@ func TrainJobGetLog(ctx *context.APIContext) { | |||
| var jobID = ctx.Params(":jobid") | |||
| var versionName = ctx.Query("version_name") | |||
| // var logFileName = ctx.Query("file_name") | |||
| var baseLine = ctx.Query("base_line") | |||
| var order = ctx.Query("order") | |||
| var lines = ctx.Query("lines") | |||
| @@ -222,14 +222,14 @@ func DelTrainJobVersion(ctx *context.APIContext) { | |||
| } | |||
| //获取删除后的版本数量 | |||
| repo := ctx.Repo.Repository | |||
| var jobTypes []string | |||
| jobTypes = append(jobTypes, string(models.JobTypeTrain)) | |||
| repo := ctx.Repo.Repository | |||
| VersionTaskList, VersionListCount, err := models.CloudbrainsVersionList(&models.CloudbrainsOptions{ | |||
| RepoID: repo.ID, | |||
| Type: models.TypeCloudBrainTwo, | |||
| RepoID: repo.ID, | |||
| Type: models.TypeCloudBrainTwo, | |||
| JobTypes: jobTypes, | |||
| JobID: jobID, | |||
| JobID: jobID, | |||
| }) | |||
| if err != nil { | |||
| ctx.ServerError("get VersionListCount failed", err) | |||
| @@ -301,7 +301,80 @@ func ModelList(ctx *context.APIContext) { | |||
| log.Error("GetCloudbrainByJobID(%s) failed:%v", task.JobName, err.Error()) | |||
| return | |||
| } | |||
| models, err := storage.GetObsListObject(task.JobName, parentDir, versionName) | |||
| models, err := storage.GetObsListObject(task.JobName, "output/", parentDir, versionName) | |||
| 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 GetModelArtsInferenceJob(ctx *context.APIContext) { | |||
| var ( | |||
| err error | |||
| ) | |||
| jobID := ctx.Params(":jobid") | |||
| job, err := models.GetCloudbrainByJobID(jobID) | |||
| 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 = util.AddZero(result.Duration/3600000) + ":" + util.AddZero(result.Duration%3600000/60000) + ":" + util.AddZero(result.Duration%60000/1000) | |||
| } else { | |||
| job.TrainJobDuration = "00:00:00" | |||
| } | |||
| err = models.UpdateInferenceJob(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 ResultList(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 | |||
| } | |||
| models, err := storage.GetObsListObject(task.JobName, "result/", parentDir, versionName) | |||
| if err != nil { | |||
| log.Info("get TrainJobListModel failed:", err) | |||
| ctx.ServerError("GetObsListObject:", err) | |||
| @@ -12,6 +12,7 @@ import ( | |||
| "code.gitea.io/gitea/models" | |||
| "code.gitea.io/gitea/modules/log" | |||
| "code.gitea.io/gitea/modules/repository" | |||
| "code.gitea.io/gitea/modules/context" | |||
| "code.gitea.io/gitea/modules/setting" | |||
| @@ -640,3 +641,26 @@ func getTotalPage(total int64, pageSize int) int { | |||
| return int(total)/pageSize + another | |||
| } | |||
| func ProjectNumVisit(ctx *context.APIContext) { | |||
| var ( | |||
| err error | |||
| ) | |||
| var userName = ctx.Query("user") | |||
| var projectName = ctx.Query("project") | |||
| var beginTime = ctx.Query("begintime") | |||
| var endTime = ctx.Query("endtime") | |||
| var ProjectNumVisits int | |||
| ProjectNumVisits, err = repository.AppointProjectView(userName, projectName, beginTime, endTime) //访问量 | |||
| if err != nil { | |||
| ctx.NotFound(err) | |||
| } | |||
| log.Info("ProjectNumVisits is:", ProjectNumVisits) | |||
| ctx.JSON(http.StatusOK, map[string]interface{}{ | |||
| "ProjectNumVisits": ProjectNumVisits, | |||
| "StatusOK": 0, | |||
| }) | |||
| } | |||
| @@ -146,7 +146,8 @@ func SaveModel(ctx *context.Context) { | |||
| if !trainTaskCreate { | |||
| if !ctx.Repo.CanWrite(models.UnitTypeModelManage) { | |||
| ctx.ServerError("No right.", errors.New(ctx.Tr("repo.model_noright"))) | |||
| //ctx.NotFound(ctx.Req.URL.RequestURI(), nil) | |||
| ctx.JSON(403, ctx.Tr("repo.model_noright")) | |||
| return | |||
| } | |||
| } | |||
| @@ -209,20 +210,11 @@ func DeleteModel(ctx *context.Context) { | |||
| }) | |||
| } | |||
| } | |||
| func isCanDeleteOrDownload(ctx *context.Context, model *models.AiModelManage) bool { | |||
| if ctx.User.IsAdmin || ctx.User.ID == model.UserId { | |||
| return true | |||
| } | |||
| if ctx.Repo.IsOwner() { | |||
| return true | |||
| } | |||
| return false | |||
| } | |||
| func deleteModelByID(ctx *context.Context, id string) error { | |||
| log.Info("delete model start. id=" + id) | |||
| model, err := models.QueryModelById(id) | |||
| if !isCanDeleteOrDownload(ctx, model) { | |||
| if !isCanDelete(ctx, model.UserId) { | |||
| return errors.New(ctx.Tr("repo.model_noright")) | |||
| } | |||
| if err == nil { | |||
| @@ -278,8 +270,8 @@ func DownloadMultiModelFile(ctx *context.Context) { | |||
| ctx.ServerError("no such model:", err) | |||
| return | |||
| } | |||
| if !isCanDeleteOrDownload(ctx, task) { | |||
| ctx.ServerError("no right.", errors.New(ctx.Tr("repo.model_noright"))) | |||
| if !isOper(ctx, task.UserId) { | |||
| ctx.NotFound(ctx.Req.URL.RequestURI(), nil) | |||
| return | |||
| } | |||
| @@ -371,7 +363,16 @@ func DownloadSingleModelFile(ctx *context.Context) { | |||
| parentDir := ctx.Query("parentDir") | |||
| fileName := ctx.Query("fileName") | |||
| path := Model_prefix + models.AttachmentRelativePath(id) + "/" + parentDir + fileName | |||
| task, err := models.QueryModelById(id) | |||
| if err != nil { | |||
| log.Error("no such model!", err.Error()) | |||
| ctx.ServerError("no such model:", err) | |||
| return | |||
| } | |||
| if !isOper(ctx, task.UserId) { | |||
| ctx.NotFound(ctx.Req.URL.RequestURI(), nil) | |||
| return | |||
| } | |||
| if setting.PROXYURL != "" { | |||
| body, err := storage.ObsDownloadAFile(setting.Bucket, path) | |||
| if err != nil { | |||
| @@ -414,6 +415,8 @@ func ShowModelInfo(ctx *context.Context) { | |||
| ctx.Data["ID"] = ctx.Query("ID") | |||
| ctx.Data["name"] = ctx.Query("name") | |||
| ctx.Data["isModelManage"] = true | |||
| ctx.Data["ModelManageAccess"] = ctx.Repo.CanWrite(models.UnitTypeModelManage) | |||
| ctx.HTML(200, tplModelInfo) | |||
| } | |||
| @@ -426,6 +429,7 @@ func ShowSingleModel(ctx *context.Context) { | |||
| userIds := make([]int64, len(models)) | |||
| for i, model := range models { | |||
| model.IsCanOper = isOper(ctx, model.UserId) | |||
| model.IsCanDelete = isCanDelete(ctx, model.UserId) | |||
| userIds[i] = model.UserId | |||
| } | |||
| userNameMap := queryUserName(userIds) | |||
| @@ -468,6 +472,7 @@ func ShowOneVersionOtherModel(ctx *context.Context) { | |||
| userIds := make([]int64, len(aimodels)) | |||
| for i, model := range aimodels { | |||
| model.IsCanOper = isOper(ctx, model.UserId) | |||
| model.IsCanDelete = isCanDelete(ctx, model.UserId) | |||
| userIds[i] = model.UserId | |||
| } | |||
| userNameMap := queryUserName(userIds) | |||
| @@ -487,8 +492,7 @@ func ShowOneVersionOtherModel(ctx *context.Context) { | |||
| } | |||
| } | |||
| func ShowModelTemplate(ctx *context.Context) { | |||
| ctx.Data["isModelManage"] = true | |||
| func SetModelCount(ctx *context.Context) { | |||
| repoId := ctx.Repo.Repository.ID | |||
| Type := -1 | |||
| _, count, _ := models.QueryModel(&models.AiModelQueryOptions{ | |||
| @@ -501,10 +505,15 @@ func ShowModelTemplate(ctx *context.Context) { | |||
| New: MODEL_LATEST, | |||
| }) | |||
| ctx.Data["MODEL_COUNT"] = count | |||
| } | |||
| func ShowModelTemplate(ctx *context.Context) { | |||
| ctx.Data["isModelManage"] = true | |||
| repoId := ctx.Repo.Repository.ID | |||
| SetModelCount(ctx) | |||
| ctx.Data["ModelManageAccess"] = ctx.Repo.CanWrite(models.UnitTypeModelManage) | |||
| _, trainCount, _ := models.QueryModelTrainJobList(repoId) | |||
| log.Info("query train count=" + fmt.Sprint(trainCount)) | |||
| ctx.Data["TRAIN_COUNT"] = trainCount | |||
| ctx.HTML(200, tplModelManageIndex) | |||
| } | |||
| @@ -520,11 +529,24 @@ func isQueryRight(ctx *context.Context) bool { | |||
| } | |||
| } | |||
| func isCanDelete(ctx *context.Context, modelUserId int64) bool { | |||
| if ctx.User == nil { | |||
| return false | |||
| } | |||
| if ctx.User.IsAdmin || ctx.User.ID == modelUserId { | |||
| return true | |||
| } | |||
| if ctx.Repo.IsOwner() { | |||
| return true | |||
| } | |||
| return false | |||
| } | |||
| func isOper(ctx *context.Context, modelUserId int64) bool { | |||
| if ctx.User == nil { | |||
| return false | |||
| } | |||
| if ctx.User.IsAdmin || ctx.Repo.IsOwner() || ctx.User.ID == modelUserId { | |||
| if ctx.User.IsAdmin || ctx.User.ID == modelUserId { | |||
| return true | |||
| } | |||
| return false | |||
| @@ -533,7 +555,7 @@ func isOper(ctx *context.Context, modelUserId int64) bool { | |||
| func ShowModelPageInfo(ctx *context.Context) { | |||
| log.Info("ShowModelInfo start.") | |||
| if !isQueryRight(ctx) { | |||
| ctx.ServerError("no right.", errors.New(ctx.Tr("repo.model_noright"))) | |||
| ctx.NotFound(ctx.Req.URL.RequestURI(), nil) | |||
| return | |||
| } | |||
| page := ctx.QueryInt("page") | |||
| @@ -563,6 +585,7 @@ func ShowModelPageInfo(ctx *context.Context) { | |||
| userIds := make([]int64, len(modelResult)) | |||
| for i, model := range modelResult { | |||
| model.IsCanOper = isOper(ctx, model.UserId) | |||
| model.IsCanDelete = isCanDelete(ctx, model.UserId) | |||
| userIds[i] = model.UserId | |||
| } | |||
| @@ -603,8 +626,9 @@ func ModifyModelInfo(ctx *context.Context) { | |||
| ctx.ServerError("no such model:", err) | |||
| return | |||
| } | |||
| if !isCanDeleteOrDownload(ctx, task) { | |||
| ctx.ServerError("no right.", errors.New(ctx.Tr("repo.model_noright"))) | |||
| if !isOper(ctx, task.UserId) { | |||
| ctx.NotFound(ctx.Req.URL.RequestURI(), nil) | |||
| //ctx.ServerError("no right.", errors.New(ctx.Tr("repo.model_noright"))) | |||
| return | |||
| } | |||
| @@ -1,15 +1,18 @@ | |||
| package repo | |||
| import ( | |||
| "archive/zip" | |||
| "encoding/json" | |||
| "errors" | |||
| "io" | |||
| "io/ioutil" | |||
| "net/http" | |||
| "os" | |||
| "path" | |||
| "strconv" | |||
| "strings" | |||
| "time" | |||
| "unicode/utf8" | |||
| "code.gitea.io/gitea/models" | |||
| "code.gitea.io/gitea/modules/auth" | |||
| @@ -37,6 +40,10 @@ const ( | |||
| tplModelArtsTrainJobNew base.TplName = "repo/modelarts/trainjob/new" | |||
| tplModelArtsTrainJobShow base.TplName = "repo/modelarts/trainjob/show" | |||
| tplModelArtsTrainJobVersionNew base.TplName = "repo/modelarts/trainjob/version_new" | |||
| tplModelArtsInferenceJobIndex base.TplName = "repo/modelarts/inferencejob/index" | |||
| tplModelArtsInferenceJobNew base.TplName = "repo/modelarts/inferencejob/new" | |||
| tplModelArtsInferenceJobShow base.TplName = "repo/modelarts/inferencejob/show" | |||
| ) | |||
| func DebugJobIndex(ctx *context.Context) { | |||
| @@ -49,6 +56,7 @@ func DebugJobIndex(ctx *context.Context) { | |||
| page = 1 | |||
| } | |||
| debugType := modelarts.DebugType | |||
| jobTypeNot := false | |||
| if debugListType == models.GPUResource { | |||
| debugType = models.TypeCloudBrainOne | |||
| } else if debugListType == models.NPUResource { | |||
| @@ -56,7 +64,7 @@ func DebugJobIndex(ctx *context.Context) { | |||
| } | |||
| var jobTypes []string | |||
| jobTypes = append(jobTypes, string(models.JobTypeSnn4imagenet), string(models.JobTypeDebug), string(models.JobTypeBrainScore)) | |||
| jobTypes = append(jobTypes, string(models.JobTypeBenchmark), string(models.JobTypeSnn4imagenet), string(models.JobTypeBrainScore), string(models.JobTypeDebug)) | |||
| ciTasks, count, err := models.Cloudbrains(&models.CloudbrainsOptions{ | |||
| ListOptions: models.ListOptions{ | |||
| Page: page, | |||
| @@ -64,7 +72,7 @@ func DebugJobIndex(ctx *context.Context) { | |||
| }, | |||
| RepoID: repo.ID, | |||
| Type: debugType, | |||
| JobTypeNot: false, | |||
| JobTypeNot: jobTypeNot, | |||
| JobTypes: jobTypes, | |||
| }) | |||
| if err != nil { | |||
| @@ -379,7 +387,7 @@ func TrainJobIndex(ctx *context.Context) { | |||
| RepoID: repo.ID, | |||
| Type: models.TypeCloudBrainTwo, | |||
| JobTypeNot: false, | |||
| JobTypes: jobTypes, | |||
| JobTypes: jobTypes, | |||
| IsLatestVersion: modelarts.IsLatestVersion, | |||
| }) | |||
| if err != nil { | |||
| @@ -753,7 +761,7 @@ func versionErrorDataPrepare(ctx *context.Context, form auth.CreateModelArtsTrai | |||
| func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) { | |||
| ctx.Data["PageIsTrainJob"] = true | |||
| VersionOutputPath := modelarts.GetVersionOutputPathByTotalVersionCount(modelarts.TotalVersionCount) | |||
| VersionOutputPath := modelarts.GetOutputPathByCount(modelarts.TotalVersionCount) | |||
| jobName := form.JobName | |||
| uuid := form.Attachment | |||
| description := form.Description | |||
| @@ -798,18 +806,11 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||
| 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) | |||
| // } | |||
| os.RemoveAll(codeLocalPath) | |||
| _, err = ioutil.ReadDir(codeLocalPath) | |||
| if err == nil { | |||
| os.RemoveAll(codeLocalPath) | |||
| } | |||
| gitRepo, _ := git.OpenRepository(repo.RepoPath()) | |||
| commitID, _ := gitRepo.GetBranchCommitID(branch_name) | |||
| @@ -977,7 +978,7 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ | |||
| ctx.ServerError("GetCloudbrainByJobIDAndIsLatestVersion faild:", err) | |||
| return | |||
| } | |||
| VersionOutputPath := modelarts.GetVersionOutputPathByTotalVersionCount(latestTask.TotalVersionCount + 1) | |||
| VersionOutputPath := modelarts.GetOutputPathByCount(latestTask.TotalVersionCount + 1) | |||
| jobName := form.JobName | |||
| uuid := form.Attachment | |||
| @@ -1015,18 +1016,17 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ | |||
| 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) | |||
| // } | |||
| os.RemoveAll(codeLocalPath) | |||
| _, err = ioutil.ReadDir(codeLocalPath) | |||
| if err == nil { | |||
| os.RemoveAll(codeLocalPath) | |||
| } else { | |||
| log.Error("创建任务失败,原代码还未删除,请重试!: %s (%v)", repo.FullName(), err) | |||
| versionErrorDataPrepare(ctx, form) | |||
| ctx.RenderWithErr("创建任务失败,原代码还未删除,请重试!", tplModelArtsTrainJobVersionNew, &form) | |||
| return | |||
| } | |||
| // os.RemoveAll(codeLocalPath) | |||
| gitRepo, _ := git.OpenRepository(repo.RepoPath()) | |||
| commitID, _ := gitRepo.GetBranchCommitID(branch_name) | |||
| @@ -1268,6 +1268,42 @@ func paramCheckCreateTrainJob(form auth.CreateModelArtsTrainJobForm) error { | |||
| return nil | |||
| } | |||
| func paramCheckCreateInferenceJob(form auth.CreateModelArtsInferenceJobForm) error { | |||
| if !strings.HasSuffix(form.BootFile, ".py") { | |||
| log.Error("the boot file(%s) must be a python file", form.BootFile) | |||
| return errors.New("启动文件必须是python文件") | |||
| } | |||
| if form.WorkServerNumber > 25 || form.WorkServerNumber < 1 { | |||
| log.Error("the WorkServerNumber(%d) must be in (1,25)", form.WorkServerNumber) | |||
| return errors.New("计算节点数必须在1-25之间") | |||
| } | |||
| if form.ModelName == "" { | |||
| log.Error("the ModelName(%d) must not be nil", form.ModelName) | |||
| return errors.New("模型名称不能为空") | |||
| } | |||
| if form.ModelVersion == "" { | |||
| log.Error("the ModelVersion(%d) must not be nil", form.ModelVersion) | |||
| return errors.New("模型版本不能为空") | |||
| } | |||
| if form.CkptName == "" { | |||
| log.Error("the CkptName(%d) must not be nil", form.CkptName) | |||
| return errors.New("权重文件不能为空") | |||
| } | |||
| if form.BranchName == "" { | |||
| log.Error("the Branch(%d) must not be nil", form.BranchName) | |||
| return errors.New("分支名不能为空") | |||
| } | |||
| if utf8.RuneCountInString(form.Description) > 255 { | |||
| log.Error("the Description length(%d) must not more than 255", form.Description) | |||
| return errors.New("描述字符不能超过255个字符") | |||
| } | |||
| return nil | |||
| } | |||
| func TrainJobShow(ctx *context.Context) { | |||
| ctx.Data["PageIsCloudBrain"] = true | |||
| var jobID = ctx.Params(":jobid") | |||
| @@ -1285,10 +1321,10 @@ func TrainJobShow(ctx *context.Context) { | |||
| Page: page, | |||
| PageSize: setting.UI.IssuePagingNum, | |||
| }, | |||
| RepoID: repo.ID, | |||
| Type: models.TypeCloudBrainTwo, | |||
| RepoID: repo.ID, | |||
| Type: models.TypeCloudBrainTwo, | |||
| JobTypes: jobTypes, | |||
| JobID: jobID, | |||
| JobID: jobID, | |||
| }) | |||
| if err != nil { | |||
| @@ -1402,10 +1438,10 @@ func TrainJobDel(ctx *context.Context) { | |||
| var jobTypes []string | |||
| jobTypes = append(jobTypes, string(models.JobTypeTrain)) | |||
| VersionListTasks, _, err := models.CloudbrainsVersionList(&models.CloudbrainsOptions{ | |||
| RepoID: repo.ID, | |||
| Type: models.TypeCloudBrainTwo, | |||
| RepoID: repo.ID, | |||
| Type: models.TypeCloudBrainTwo, | |||
| JobTypes: jobTypes, | |||
| JobID: jobID, | |||
| JobID: jobID, | |||
| }) | |||
| if err != nil { | |||
| ctx.ServerError("get VersionListTasks failed", err) | |||
| @@ -1527,6 +1563,427 @@ func getConfigList(perPage, page int, sortBy, order, searchContent, configType s | |||
| return list, nil | |||
| } | |||
| func InferenceJobCreate(ctx *context.Context, form auth.CreateModelArtsInferenceJobForm) { | |||
| ctx.Data["PageIsTrainJob"] = true | |||
| VersionOutputPath := modelarts.GetOutputPathByCount(modelarts.TotalVersionCount) | |||
| 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 | |||
| repo := ctx.Repo.Repository | |||
| codeLocalPath := setting.JobPath + jobName + modelarts.CodePath | |||
| codeObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.CodePath | |||
| resultObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.ResultPath + 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 | |||
| FlavorName := form.FlavorName | |||
| EngineName := form.EngineName | |||
| LabelName := form.LabelName | |||
| isLatestVersion := modelarts.IsLatestVersion | |||
| VersionCount := modelarts.VersionCount | |||
| trainUrl := form.TrainUrl | |||
| modelName := form.ModelName | |||
| modelVersion := form.ModelVersion | |||
| ckptName := form.CkptName | |||
| ckptUrl := form.TrainUrl + form.CkptName | |||
| if err := paramCheckCreateInferenceJob(form); err != nil { | |||
| log.Error("paramCheckCreateInferenceJob failed:(%v)", err) | |||
| inferenceJobErrorNewDataPrepare(ctx, form) | |||
| ctx.RenderWithErr(err.Error(), tplModelArtsInferenceJobNew, &form) | |||
| return | |||
| } | |||
| count, err := models.GetCloudbrainInferenceJobCountByUserID(ctx.User.ID) | |||
| if err != nil { | |||
| log.Error("GetCloudbrainInferenceJobCountByUserID failed:%v", err, ctx.Data["MsgID"]) | |||
| inferenceJobErrorNewDataPrepare(ctx, form) | |||
| ctx.RenderWithErr("system error", tplModelArtsInferenceJobNew, &form) | |||
| return | |||
| } else { | |||
| if count >= 1 { | |||
| log.Error("the user already has running or waiting inference task", ctx.Data["MsgID"]) | |||
| inferenceJobErrorNewDataPrepare(ctx, form) | |||
| ctx.RenderWithErr("you have already a running or waiting inference task, can not create more", tplModelArtsInferenceJobNew, &form) | |||
| 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) | |||
| inferenceJobErrorNewDataPrepare(ctx, form) | |||
| ctx.RenderWithErr("创建任务失败,服务器超时!", tplModelArtsInferenceJobNew, &form) | |||
| return | |||
| } | |||
| //todo: upload code (send to file_server todo this work?) | |||
| if err := obsMkdir(setting.CodePathPrefix + jobName + modelarts.ResultPath + VersionOutputPath + "/"); err != nil { | |||
| log.Error("Failed to obsMkdir_result: %s (%v)", repo.FullName(), err) | |||
| inferenceJobErrorNewDataPrepare(ctx, form) | |||
| ctx.RenderWithErr("Failed to obsMkdir_result", tplModelArtsInferenceJobNew, &form) | |||
| return | |||
| } | |||
| if err := obsMkdir(setting.CodePathPrefix + jobName + modelarts.LogPath + VersionOutputPath + "/"); err != nil { | |||
| log.Error("Failed to obsMkdir_log: %s (%v)", repo.FullName(), err) | |||
| inferenceJobErrorNewDataPrepare(ctx, form) | |||
| ctx.RenderWithErr("Failed to obsMkdir_log", tplModelArtsInferenceJobNew, &form) | |||
| return | |||
| } | |||
| if err := uploadCodeToObs(codeLocalPath, jobName, ""); err != nil { | |||
| log.Error("Failed to uploadCodeToObs: %s (%v)", repo.FullName(), err) | |||
| inferenceJobErrorNewDataPrepare(ctx, form) | |||
| ctx.RenderWithErr("Failed to uploadCodeToObs", tplModelArtsInferenceJobNew, &form) | |||
| return | |||
| } | |||
| //todo: del local code? | |||
| var parameters models.Parameters | |||
| param := make([]models.Parameter, 0) | |||
| param = append(param, models.Parameter{ | |||
| Label: modelarts.ResultUrl, | |||
| Value: "s3:/" + resultObsPath, | |||
| }, models.Parameter{ | |||
| Label: modelarts.CkptUrl, | |||
| Value: "s3:/" + ckptUrl, | |||
| }) | |||
| if len(params) != 0 { | |||
| err := json.Unmarshal([]byte(params), ¶meters) | |||
| if err != nil { | |||
| log.Error("Failed to Unmarshal params: %s (%v)", params, err) | |||
| inferenceJobErrorNewDataPrepare(ctx, form) | |||
| ctx.RenderWithErr("运行参数错误", tplModelArtsInferenceJobNew, &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, | |||
| }) | |||
| } | |||
| } | |||
| } | |||
| req := &modelarts.GenerateInferenceJobReq{ | |||
| JobName: jobName, | |||
| DataUrl: dataPath, | |||
| Description: description, | |||
| CodeObsPath: codeObsPath, | |||
| BootFileUrl: codeObsPath + bootFile, | |||
| BootFile: bootFile, | |||
| TrainUrl: trainUrl, | |||
| FlavorCode: flavorCode, | |||
| WorkServerNumber: workServerNumber, | |||
| EngineID: int64(engineID), | |||
| LogUrl: logObsPath, | |||
| PoolID: poolID, | |||
| Uuid: uuid, | |||
| Parameters: param, //modelarts训练时用到 | |||
| CommitID: commitID, | |||
| BranchName: branch_name, | |||
| Params: form.Params, | |||
| FlavorName: FlavorName, | |||
| EngineName: EngineName, | |||
| LabelName: LabelName, | |||
| IsLatestVersion: isLatestVersion, | |||
| VersionCount: VersionCount, | |||
| TotalVersionCount: modelarts.TotalVersionCount, | |||
| ModelName: modelName, | |||
| ModelVersion: modelVersion, | |||
| CkptName: ckptName, | |||
| ResultUrl: resultObsPath, | |||
| } | |||
| //将params转换Parameters.Parameter,出错时返回给前端 | |||
| // var Parameters modelarts.Parameters | |||
| // if err := json.Unmarshal([]byte(params), &Parameters); err != nil { | |||
| // ctx.ServerError("json.Unmarshal failed:", err) | |||
| // return | |||
| // } | |||
| err = modelarts.GenerateInferenceJob(ctx, req) | |||
| if err != nil { | |||
| log.Error("GenerateTrainJob failed:%v", err.Error()) | |||
| inferenceJobErrorNewDataPrepare(ctx, form) | |||
| ctx.RenderWithErr(err.Error(), tplModelArtsInferenceJobNew, &form) | |||
| return | |||
| } | |||
| ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/inference-job") | |||
| } | |||
| func InferenceJobIndex(ctx *context.Context) { | |||
| MustEnableModelArts(ctx) | |||
| repo := ctx.Repo.Repository | |||
| page := ctx.QueryInt("page") | |||
| if page <= 0 { | |||
| page = 1 | |||
| } | |||
| var jobTypes []string | |||
| jobTypes = append(jobTypes, string(models.JobTypeInference)) | |||
| tasks, count, err := models.Cloudbrains(&models.CloudbrainsOptions{ | |||
| ListOptions: models.ListOptions{ | |||
| Page: page, | |||
| PageSize: setting.UI.IssuePagingNum, | |||
| }, | |||
| RepoID: repo.ID, | |||
| Type: models.TypeCloudBrainTwo, | |||
| JobTypes: jobTypes, | |||
| }) | |||
| if err != nil { | |||
| ctx.ServerError("Cloudbrain", err) | |||
| return | |||
| } | |||
| for i, task := range tasks { | |||
| tasks[i].CanDel = cloudbrain.CanDeleteJob(ctx, &task.Cloudbrain) | |||
| tasks[i].CanModify = cloudbrain.CanModifyJob(ctx, &task.Cloudbrain) | |||
| tasks[i].ComputeResource = models.NPUResource | |||
| } | |||
| repoId := ctx.Repo.Repository.ID | |||
| Type := -1 | |||
| _, model_count, _ := models.QueryModel(&models.AiModelQueryOptions{ | |||
| ListOptions: models.ListOptions{ | |||
| Page: 1, | |||
| PageSize: 2, | |||
| }, | |||
| RepoID: repoId, | |||
| Type: Type, | |||
| New: MODEL_LATEST, | |||
| }) | |||
| ctx.Data["MODEL_COUNT"] = model_count | |||
| pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, 5) | |||
| pager.SetDefaultParams(ctx) | |||
| ctx.Data["Page"] = pager | |||
| ctx.Data["PageIsCloudBrain"] = true | |||
| ctx.Data["Tasks"] = tasks | |||
| ctx.Data["CanCreate"] = cloudbrain.CanCreateOrDebugJob(ctx) | |||
| ctx.Data["RepoIsEmpty"] = repo.IsEmpty | |||
| ctx.HTML(200, tplModelArtsInferenceJobIndex) | |||
| } | |||
| func InferenceJobNew(ctx *context.Context) { | |||
| err := inferenceJobNewDataPrepare(ctx) | |||
| if err != nil { | |||
| ctx.ServerError("get new inference-job info failed", err) | |||
| return | |||
| } | |||
| ctx.HTML(200, tplModelArtsInferenceJobNew) | |||
| } | |||
| func inferenceJobNewDataPrepare(ctx *context.Context) error { | |||
| ctx.Data["PageIsCloudBrain"] = true | |||
| t := time.Now() | |||
| var jobName = cutString(ctx.User.Name, 5) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:] | |||
| ctx.Data["job_name"] = jobName | |||
| attachs, err := models.GetModelArtsTrainAttachments(ctx.User.ID) | |||
| if err != nil { | |||
| ctx.ServerError("GetAllUserAttachments failed:", err) | |||
| return err | |||
| } | |||
| ctx.Data["attachments"] = attachs | |||
| var resourcePools modelarts.ResourcePool | |||
| if err = json.Unmarshal([]byte(setting.ResourcePools), &resourcePools); err != nil { | |||
| ctx.ServerError("json.Unmarshal failed:", err) | |||
| return err | |||
| } | |||
| ctx.Data["resource_pools"] = resourcePools.Info | |||
| var engines modelarts.Engine | |||
| if err = json.Unmarshal([]byte(setting.Engines), &engines); err != nil { | |||
| ctx.ServerError("json.Unmarshal failed:", err) | |||
| return err | |||
| } | |||
| ctx.Data["engines"] = engines.Info | |||
| var versionInfos modelarts.VersionInfo | |||
| if err = json.Unmarshal([]byte(setting.EngineVersions), &versionInfos); err != nil { | |||
| ctx.ServerError("json.Unmarshal failed:", err) | |||
| return err | |||
| } | |||
| ctx.Data["engine_versions"] = versionInfos.Version | |||
| 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 | |||
| ctx.Data["params"] = "" | |||
| ctx.Data["branchName"] = ctx.Repo.BranchName | |||
| 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 | |||
| repoId := ctx.Repo.Repository.ID | |||
| Type := -1 | |||
| _, model_count, _ := models.QueryModel(&models.AiModelQueryOptions{ | |||
| ListOptions: models.ListOptions{ | |||
| Page: 1, | |||
| PageSize: 2, | |||
| }, | |||
| RepoID: repoId, | |||
| Type: Type, | |||
| New: MODEL_LATEST, | |||
| }) | |||
| ctx.Data["MODEL_COUNT"] = model_count | |||
| return nil | |||
| } | |||
| func inferenceJobErrorNewDataPrepare(ctx *context.Context, form auth.CreateModelArtsInferenceJobForm) error { | |||
| ctx.Data["PageIsCloudBrain"] = true | |||
| t := time.Now() | |||
| var jobName = "inference" + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:] | |||
| ctx.Data["job_name"] = jobName | |||
| attachs, err := models.GetModelArtsTrainAttachments(ctx.User.ID) | |||
| if err != nil { | |||
| ctx.ServerError("GetAllUserAttachments failed:", err) | |||
| return err | |||
| } | |||
| ctx.Data["attachments"] = attachs | |||
| var resourcePools modelarts.ResourcePool | |||
| if err = json.Unmarshal([]byte(setting.ResourcePools), &resourcePools); err != nil { | |||
| ctx.ServerError("json.Unmarshal failed:", err) | |||
| return err | |||
| } | |||
| ctx.Data["resource_pools"] = resourcePools.Info | |||
| var engines modelarts.Engine | |||
| if err = json.Unmarshal([]byte(setting.Engines), &engines); err != nil { | |||
| ctx.ServerError("json.Unmarshal failed:", err) | |||
| return err | |||
| } | |||
| ctx.Data["engines"] = engines.Info | |||
| var versionInfos modelarts.VersionInfo | |||
| if err = json.Unmarshal([]byte(setting.EngineVersions), &versionInfos); err != nil { | |||
| ctx.ServerError("json.Unmarshal failed:", err) | |||
| return err | |||
| } | |||
| ctx.Data["engine_versions"] = versionInfos.Version | |||
| 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 | |||
| configList, err := getConfigList(modelarts.PerPage, 1, modelarts.SortByCreateTime, "desc", "", modelarts.ConfigTypeCustom) | |||
| if err != nil { | |||
| ctx.ServerError("getConfigList failed:", err) | |||
| return err | |||
| } | |||
| var Parameters modelarts.Parameters | |||
| if err = json.Unmarshal([]byte(form.Params), &Parameters); err != nil { | |||
| ctx.ServerError("json.Unmarshal failed:", err) | |||
| return err | |||
| } | |||
| ctx.Data["params"] = Parameters.Parameter | |||
| ctx.Data["config_list"] = configList.ParaConfigs | |||
| ctx.Data["bootFile"] = form.BootFile | |||
| ctx.Data["uuid"] = form.Attachment | |||
| ctx.Data["branch_name"] = form.BranchName | |||
| ctx.Data["model_name"] = form.ModelName | |||
| ctx.Data["model_version"] = form.ModelVersion | |||
| ctx.Data["ckpt_name"] = form.CkptName | |||
| ctx.Data["train_url"] = form.TrainUrl | |||
| return nil | |||
| } | |||
| func InferenceJobShow(ctx *context.Context) { | |||
| ctx.Data["PageIsCloudBrain"] = true | |||
| var jobID = ctx.Params(":jobid") | |||
| page := ctx.QueryInt("page") | |||
| if page <= 0 { | |||
| page = 1 | |||
| } | |||
| task, err := models.GetCloudbrainByJobID(jobID) | |||
| if err != nil { | |||
| log.Error("GetInferenceTask(%s) failed:%v", jobID, err.Error()) | |||
| ctx.RenderWithErr(err.Error(), tplModelArtsInferenceJobShow, nil) | |||
| return | |||
| } | |||
| //设置权限 | |||
| canNewJob, err := canUserCreateTrainJobVersion(ctx, task.UserID) | |||
| if err != nil { | |||
| ctx.ServerError("canNewJob failed", err) | |||
| return | |||
| } | |||
| ctx.Data["canNewJob"] = canNewJob | |||
| //将运行参数转化为epoch_size = 3, device_target = Ascend的格式 | |||
| var parameters models.Parameters | |||
| err = json.Unmarshal([]byte(task.Parameters), ¶meters) | |||
| if err != nil { | |||
| log.Error("Failed to Unmarshal Parameters: %s (%v)", task.Parameters, err) | |||
| trainJobNewDataPrepare(ctx) | |||
| return | |||
| } | |||
| if len(parameters.Parameter) > 0 { | |||
| paramTemp := "" | |||
| for _, Parameter := range parameters.Parameter { | |||
| param := Parameter.Label + " = " + Parameter.Value + "; " | |||
| paramTemp = paramTemp + param | |||
| } | |||
| task.Parameters = paramTemp[:len(paramTemp)-2] | |||
| } else { | |||
| task.Parameters = "" | |||
| } | |||
| LabelName := strings.Fields(task.LabelName) | |||
| ctx.Data["labelName"] = LabelName | |||
| ctx.Data["jobID"] = jobID | |||
| ctx.Data["jobName"] = task.JobName | |||
| ctx.Data["task"] = task | |||
| tempUids := []int64{} | |||
| tempUids = append(tempUids, task.UserID) | |||
| JobCreater, err := models.GetUserNamesByIDs(tempUids) | |||
| if err != nil { | |||
| log.Error("GetUserNamesByIDs (WhitelistUserIDs): %v", err) | |||
| } | |||
| ctx.Data["userName"] = JobCreater[0] | |||
| ctx.HTML(http.StatusOK, tplModelArtsInferenceJobShow) | |||
| } | |||
| func ModelDownload(ctx *context.Context) { | |||
| var ( | |||
| err error | |||
| @@ -1555,6 +2012,31 @@ func ModelDownload(ctx *context.Context) { | |||
| http.Redirect(ctx.Resp, ctx.Req.Request, url, http.StatusMovedPermanently) | |||
| } | |||
| func ResultDownload(ctx *context.Context) { | |||
| var ( | |||
| err error | |||
| ) | |||
| var jobID = ctx.Params(":jobid") | |||
| versionName := ctx.Query("version_name") | |||
| parentDir := ctx.Query("parent_dir") | |||
| fileName := ctx.Query("file_name") | |||
| log.Info("DownloadResult start.") | |||
| task, err := models.GetCloudbrainByJobID(jobID) | |||
| if err != nil { | |||
| ctx.Data["error"] = err.Error() | |||
| } | |||
| path := strings.TrimPrefix(path.Join(setting.TrainJobModelPath, task.JobName, "result/", versionName, parentDir, fileName), "/") | |||
| log.Info("Download path is:%s", path) | |||
| url, err := storage.GetObsCreateSignedUrlByBucketAndKey(setting.Bucket, path) | |||
| 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) | |||
| } | |||
| func DeleteJobStorage(jobName string) error { | |||
| //delete local | |||
| localJobPath := setting.JobPath + jobName | |||
| @@ -1572,3 +2054,82 @@ func DeleteJobStorage(jobName string) error { | |||
| return nil | |||
| } | |||
| func DownloadMultiResultFile(ctx *context.Context) { | |||
| var jobID = ctx.Params(":jobid") | |||
| var versionName = ctx.Query("version_name") | |||
| task, err := models.GetCloudbrainByJobIDAndVersionName(jobID, versionName) | |||
| if err != nil { | |||
| log.Error("GetCloudbrainByJobID(%s) failed:%v", task.JobName, err.Error()) | |||
| return | |||
| } | |||
| // if !isCanDeleteOrDownload(ctx, task) { | |||
| // ctx.ServerError("no right.", errors.New(ctx.Tr("repo.model_noright"))) | |||
| // return | |||
| // } | |||
| // path := Model_prefix + models.AttachmentRelativePath(id) + "/" | |||
| path := strings.TrimPrefix(path.Join(setting.TrainJobModelPath, task.JobName, "result/", versionName), "/") + "/" | |||
| allFile, err := storage.GetAllObjectByBucketAndPrefix(setting.Bucket, path) | |||
| if err == nil { | |||
| //count++ | |||
| // models.ModifyModelDownloadCount(id) | |||
| returnFileName := task.JobName + ".zip" | |||
| ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+returnFileName) | |||
| ctx.Resp.Header().Set("Content-Type", "application/octet-stream") | |||
| w := zip.NewWriter(ctx.Resp) | |||
| defer w.Close() | |||
| for _, oneFile := range allFile { | |||
| if oneFile.IsDir { | |||
| log.Info("zip dir name:" + oneFile.FileName) | |||
| } else { | |||
| log.Info("zip file name:" + oneFile.FileName) | |||
| fDest, err := w.Create(oneFile.FileName) | |||
| if err != nil { | |||
| log.Info("create zip entry error, download file failed: %s\n", err.Error()) | |||
| ctx.ServerError("download file failed:", err) | |||
| return | |||
| } | |||
| body, err := storage.ObsDownloadAFile(setting.Bucket, path+oneFile.FileName) | |||
| if err != nil { | |||
| log.Info("download file failed: %s\n", err.Error()) | |||
| ctx.ServerError("download file failed:", err) | |||
| return | |||
| } else { | |||
| defer body.Close() | |||
| p := make([]byte, 1024) | |||
| var readErr error | |||
| var readCount int | |||
| // 读取对象内容 | |||
| for { | |||
| readCount, readErr = body.Read(p) | |||
| if readCount > 0 { | |||
| fDest.Write(p[:readCount]) | |||
| } | |||
| if readErr != nil { | |||
| break | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } else { | |||
| log.Info("error,msg=" + err.Error()) | |||
| ctx.ServerError("no file to download.", err) | |||
| } | |||
| } | |||
| func SetJobCount(ctx *context.Context) { | |||
| repoId := ctx.Repo.Repository.ID | |||
| _, jobCount, err := models.Cloudbrains(&models.CloudbrainsOptions{ | |||
| RepoID: repoId, | |||
| Type: modelarts.DebugType, | |||
| }) | |||
| if err != nil { | |||
| ctx.ServerError("Get job faild:", err) | |||
| return | |||
| } | |||
| ctx.Data["jobCount"] = jobCount | |||
| } | |||
| @@ -50,6 +50,8 @@ func Settings(ctx *context.Context) { | |||
| ctx.Data["Title"] = ctx.Tr("repo.settings") | |||
| ctx.Data["PageIsSettingsOptions"] = true | |||
| ctx.Data["ForcePrivate"] = setting.Repository.ForcePrivate | |||
| SetModelCount(ctx) | |||
| SetJobCount(ctx) | |||
| ctx.HTML(200, tplSettingsOptions) | |||
| } | |||
| @@ -57,7 +59,8 @@ func Settings(ctx *context.Context) { | |||
| func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) { | |||
| ctx.Data["Title"] = ctx.Tr("repo.settings") | |||
| ctx.Data["PageIsSettingsOptions"] = true | |||
| SetModelCount(ctx) | |||
| SetJobCount(ctx) | |||
| repo := ctx.Repo.Repository | |||
| switch ctx.Query("action") { | |||
| @@ -91,19 +91,19 @@ func queryUserDataPage(ctx *context.Context, tableName string, queryObj interfac | |||
| xlsx.SetCellValue(sheetName, "Q"+rows, formatTime) | |||
| } | |||
| //设置默认打开的表单 | |||
| xlsx.SetActiveSheet(index) | |||
| filename := sheetName + "_" + ctx.Tr("user.static."+tableName) + ".xlsx" | |||
| ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+url.QueryEscape(filename)) | |||
| ctx.Resp.Header().Set("Content-Type", "application/octet-stream") | |||
| if _, err := xlsx.WriteTo(ctx.Resp); err != nil { | |||
| log.Info("writer exel error." + err.Error()) | |||
| } | |||
| indexTotal += PAGE_SIZE | |||
| if indexTotal >= count { | |||
| break | |||
| } | |||
| } | |||
| //设置默认打开的表单 | |||
| xlsx.SetActiveSheet(index) | |||
| filename := sheetName + "_" + ctx.Tr("user.static."+tableName) + ".xlsx" | |||
| ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+url.QueryEscape(filename)) | |||
| ctx.Resp.Header().Set("Content-Type", "application/octet-stream") | |||
| if _, err := xlsx.WriteTo(ctx.Resp); err != nil { | |||
| log.Info("writer exel error." + err.Error()) | |||
| } | |||
| } else { | |||
| re, count := models.QueryUserStaticDataByTableName((page-1)*pageSize, pageSize, tableName, queryObj, userName) | |||
| mapInterface := make(map[string]interface{}) | |||
| @@ -1046,6 +1046,17 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
| m.Get("/para-config-list", reqRepoCloudBrainReader, repo.TrainJobGetConfigList) | |||
| }) | |||
| m.Group("/inference-job", func() { | |||
| m.Get("", reqRepoCloudBrainReader, repo.InferenceJobIndex) | |||
| m.Group("/:jobid", func() { | |||
| m.Get("", reqRepoCloudBrainReader, repo.InferenceJobShow) | |||
| m.Get("/result_download", cloudbrain.AdminOrJobCreaterRight, repo.ResultDownload) | |||
| m.Get("/downloadall", repo.DownloadMultiResultFile) | |||
| }) | |||
| m.Get("/create", reqRepoCloudBrainWriter, repo.InferenceJobNew) | |||
| m.Post("/create", reqRepoCloudBrainWriter, bindIgnErr(auth.CreateModelArtsInferenceJobForm{}), repo.InferenceJobCreate) | |||
| }) | |||
| }, context.RepoRef()) | |||
| m.Group("/blockchain", func() { | |||
| @@ -50,6 +50,7 @@ func (h *ClientsManager) Run() { | |||
| } | |||
| case message := <-models.ActionChan: | |||
| if isInOpTypes(opTypes, message.OpType) { | |||
| message.Comment = nil | |||
| LastActionsQueue.Push(message) | |||
| for _, client := range h.Clients.Keys() { | |||
| select { | |||
| @@ -34,6 +34,7 @@ | |||
| <div class="ui blue small menu compact selectcloudbrain"> | |||
| <a class="item" href="{{.RepoLink}}/debugjob?debugListType=all">{{$.i18n.Tr "repo.modelarts.notebook"}}</a> | |||
| <a class="item" href="{{.RepoLink}}/modelarts/train-job">{{$.i18n.Tr "repo.modelarts.train_job"}}</a> | |||
| <a class="item" href="{{.RepoLink}}/modelarts/inference-job">{{$.i18n.Tr "repo.modelarts.infer_job"}}</a> | |||
| <a class="active item" href="{{.RepoLink}}/cloudbrain/benchmark">{{$.i18n.Tr "repo.modelarts.evaluate_job"}}</a> | |||
| </div> | |||
| </div> | |||
| @@ -147,7 +147,7 @@ | |||
| </div> | |||
| <div class="inline required field"> | |||
| <label>任务名称</label> | |||
| <input name="job_name" id="cloudbrain_job_name" placeholder="任务名称" value="{{.job_name}}" tabindex="3" autofocus required maxlength="254"> | |||
| <input name="job_name" id="cloudbrain_job_name" placeholder="任务名称" value="{{.job_name}}" tabindex="3" autofocus required maxlength="255" onkeyup="this.value=this.value.replace(/[, ]/g,'')"> | |||
| </div> | |||
| <div class="inline required field" style="{{if ((.is_benchmark_enabled) or (.is_snn4imagenet_enabled) or (.is_brainscore_enabled))}}display:block;{{else}}display:none;{{end}}"> | |||
| @@ -192,7 +192,7 @@ | |||
| <div class="inline required field" style="position: relative;"> | |||
| <label>镜像</label> | |||
| <input type="text" list="cloudbrain_image" placeholder="选择镜像" name="image" required autofocus maxlength="254"> | |||
| <input type="text" list="cloudbrain_image" placeholder="选择镜像" name="image" required autofocus maxlength="255"> | |||
| <i class="times circle outline icon icons" style="visibility: hidden;" onclick="clearValue()"></i> | |||
| <datalist class="ui search" id="cloudbrain_image" style='width:385px;' name="image"> | |||
| {{range .images}} | |||
| @@ -225,27 +225,27 @@ | |||
| <div class="inline required field"> | |||
| <label>数据集存放路径</label> | |||
| <input name="dataset_path" id="cloudbrain_dataset_path" value="{{.dataset_path}}" tabindex="3" disabled autofocus required maxlength="254" readonly="readonly"> | |||
| <input name="dataset_path" id="cloudbrain_dataset_path" value="{{.dataset_path}}" tabindex="3" disabled autofocus required maxlength="255" readonly="readonly"> | |||
| </div> | |||
| <div class="inline required field"> | |||
| <label>模型存放路径</label> | |||
| <input name="model_path" id="cloudbrain_model_path" value="{{.model_path}}" tabindex="3" disabled autofocus required maxlength="254" readonly="readonly"> | |||
| <input name="model_path" id="cloudbrain_model_path" value="{{.model_path}}" tabindex="3" disabled autofocus required maxlength="255" readonly="readonly"> | |||
| </div> | |||
| <div class="inline required field"> | |||
| <label>代码存放路径</label> | |||
| <input name="code_path" id="cloudbrain_code_path" value="{{.code_path}}" tabindex="3" disabled autofocus required maxlength="254" readonly="readonly"> | |||
| <input name="code_path" id="cloudbrain_code_path" value="{{.code_path}}" tabindex="3" disabled autofocus required maxlength="255" readonly="readonly"> | |||
| </div> | |||
| <div class="inline required field cloudbrain_benchmark"> | |||
| <label>benchmark脚本存放路径</label> | |||
| <input name="benchmark_path" id="cloudbrain_benchmark_path" value="{{.benchmark_path}}" tabindex="3" disabled autofocus required maxlength="254" readonly="readonly"> | |||
| <input name="benchmark_path" id="cloudbrain_benchmark_path" value="{{.benchmark_path}}" tabindex="3" disabled autofocus required maxlength="255" readonly="readonly"> | |||
| </div> | |||
| <div class="inline required field cloudbrain_snn4imagenet"> | |||
| <label>snn4imagenet脚本存放路径</label> | |||
| <input name="snn4imagenet_path" id="cloudbrain_snn4imagenet_path" value="{{.snn4imagenet_path}}" tabindex="3" disabled autofocus required maxlength="254" readonly="readonly"> | |||
| <input name="snn4imagenet_path" id="cloudbrain_snn4imagenet_path" value="{{.snn4imagenet_path}}" tabindex="3" disabled autofocus required maxlength="255" readonly="readonly"> | |||
| </div> | |||
| <div class="inline required field cloudbrain_brainscore"> | |||
| <label>brainscore脚本存放路径</label> | |||
| <input name="brainscore_path" id="cloudbrain_brainscore_path" value="{{.brainscore_path}}" tabindex="3" disabled autofocus required maxlength="254" readonly="readonly"> | |||
| <input name="brainscore_path" id="cloudbrain_brainscore_path" value="{{.brainscore_path}}" tabindex="3" disabled autofocus required maxlength="255" readonly="readonly"> | |||
| </div> | |||
| <div class="inline required field" hidden> | |||
| <label>启动命令</label> | |||
| @@ -54,7 +54,7 @@ | |||
| </div> | |||
| <div class="inline field {{if .Err_Description}}error{{end}}"> | |||
| <label for="description">{{.i18n.Tr "repo.repo_desc"}}</label> | |||
| <textarea id="description" name="description" maxlength="254">{{.description}}</textarea> | |||
| <textarea id="description" name="description" maxlength="255">{{.description}}</textarea> | |||
| </div> | |||
| <div class="inline field"> | |||
| <label>{{.i18n.Tr "repo.template"}}</label> | |||
| @@ -57,7 +57,7 @@ | |||
| <div class="ui grid form segment success {{if not .Error}}hide{{end}}" id="dataset-content-edit"> | |||
| <label class="d-block">{{.i18n.Tr "dataset.title"}}</label> | |||
| <div class="sixteen wide column"> | |||
| <input name="title" placeholder='{{.i18n.Tr "dataset.title"}}' value="{{.dataset.Title}}" autofocus required maxlength="254"> | |||
| <input name="title" placeholder='{{.i18n.Tr "dataset.title"}}' value="{{.dataset.Title}}" autofocus required maxlength="255"> | |||
| </div> | |||
| <label class="d-block">{{.i18n.Tr "dataset.description"}}</label> | |||
| <div class="sixteen wide column"> | |||
| @@ -217,6 +217,7 @@ | |||
| <div class="ui blue small menu compact selectcloudbrain"> | |||
| <a class="active item" href="{{.RepoLink}}/debugjob?debugListType=all">{{$.i18n.Tr "repo.modelarts.notebook"}}</a> | |||
| <a class="item" href="{{.RepoLink}}/modelarts/train-job">{{$.i18n.Tr "repo.modelarts.train_job"}}</a> | |||
| <a class="item" href="{{.RepoLink}}/modelarts/inference-job">{{$.i18n.Tr "repo.modelarts.infer_job"}}</a> | |||
| <a class="item" href="{{.RepoLink}}/cloudbrain/benchmark">{{$.i18n.Tr "repo.modelarts.evaluate_job"}}</a> | |||
| </div> | |||
| </div> | |||
| @@ -431,12 +432,12 @@ | |||
| <div class="inline required field dis"> | |||
| <label>镜像标签:</label> | |||
| <input name="tag" id="image_tag" tabindex="3" autofocus required maxlength="254" style="width:75%"> | |||
| <input name="tag" id="image_tag" tabindex="3" autofocus required maxlength="255" style="width:75%"> | |||
| </div> | |||
| <div class="inline field"> | |||
| <label class="label_after">镜像描述:</label> | |||
| <textarea name="description" maxlength="254" rows="8" style="width:75%;margin-left: 0.2em;"></textarea> | |||
| <textarea name="description" maxlength="255" rows="8" style="width:75%;margin-left: 0.2em;"></textarea> | |||
| </div> | |||
| <div class="ui divider"></div> | |||
| <div class="inline field"> | |||
| @@ -489,6 +490,7 @@ | |||
| <script> | |||
| // 调试和评分新开窗口 | |||
| console.log({{.Tasks}}) | |||
| const {AppSubUrl, StaticUrlPrefix, csrf} = window.config; | |||
| let url={{.RepoLink}} | |||
| let getParam=getQueryVariable('debugListType') | |||
| @@ -607,7 +609,7 @@ | |||
| const jobID = job.dataset.jobid; | |||
| const repoPath = job.dataset.repopath; | |||
| const computeResource = job.dataset.resource | |||
| const initArray = ['STOPPED','FAILED','START_FAILED','CREATE_FAILED','SUCCEEDED'] | |||
| const initArray = ['STOPPED','FAILED','START_FAILED','CREATE_FAILED','SUCCEEDED','UNAVAILABLE','DELETED','RESIZE_FAILED'] | |||
| if (initArray.includes(job.textContent.trim())) { | |||
| return | |||
| @@ -15,7 +15,7 @@ | |||
| <div class="ui segment content"> | |||
| <div class="field"> | |||
| <!-- --> | |||
| <input name="title" id="issue_title" placeholder="{{.i18n.Tr "repo.milestones.title"}}" value="{{.title}}" tabindex="3" autofocus required maxlength="254"> | |||
| <input name="title" id="issue_title" placeholder="{{.i18n.Tr "repo.milestones.title"}}" value="{{.title}}" tabindex="3" autofocus required maxlength="255"> | |||
| {{if .PageIsComparePull}} | |||
| <div class="title_wip_desc">{{.i18n.Tr "repo.pulls.title_wip_desc" (index .PullRequestWorkInProgressPrefixes 0| Escape) | Safe}}</div> | |||
| {{end}} | |||
| @@ -3,7 +3,7 @@ | |||
| <h1 class="twelve wide column"> | |||
| <span class="index">#{{.Issue.Index}}</span> <span id="issue-title">{{RenderEmoji .Issue.Title}}</span> | |||
| <div id="edit-title-input" class="ui input" style="display: none"> | |||
| <input value="{{.Issue.Title}}" maxlength="254"> | |||
| <input value="{{.Issue.Title}}" maxlength="255"> | |||
| </div> | |||
| </h1> | |||
| {{if and (or .HasIssuesOrPullsWritePermission .IsIssuePoster) (not .Repository.IsArchived)}} | |||
| @@ -122,7 +122,7 @@ | |||
| </div> | |||
| <div class="inline field {{if .Err_Description}}error{{end}}"> | |||
| <label for="description">{{.i18n.Tr "repo.repo_desc"}}</label> | |||
| <textarea id="description" name="description" maxlength="254">{{.description}}</textarea> | |||
| <textarea id="description" name="description" maxlength="255">{{.description}}</textarea> | |||
| </div> | |||
| <div class="inline field"> | |||
| @@ -0,0 +1,337 @@ | |||
| <!-- 头部导航栏 --> | |||
| {{template "base/head" .}} | |||
| <style> | |||
| .fontsize14{ | |||
| font-size: 14px; | |||
| } | |||
| .padding0{ | |||
| padding: 0 !important; | |||
| } | |||
| </style> | |||
| <!-- 弹窗 --> | |||
| <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="alert"></div> | |||
| <div class="repository release dataset-list view"> | |||
| {{template "repo/header" .}} | |||
| <!-- 列表容器 --> | |||
| <div class="ui container"> | |||
| {{template "base/alert" .}} | |||
| <div class="ui two column stackable grid "> | |||
| <div class="column"> | |||
| <div class="ui blue small menu compact selectcloudbrain"> | |||
| <a class="item" href="{{.RepoLink}}/debugjob?debugListType=all">{{$.i18n.Tr "repo.modelarts.notebook"}}</a> | |||
| <a class="item" href="{{.RepoLink}}/modelarts/train-job">{{$.i18n.Tr "repo.modelarts.train_job"}}</a> | |||
| <a class="active item" href="{{.RepoLink}}/modelarts/inference-job">{{$.i18n.Tr "repo.modelarts.infer_job"}}</a> | |||
| </div> | |||
| </div> | |||
| <div class="column right aligned"> | |||
| {{if .Permission.CanWrite $.UnitTypeCloudBrain}} | |||
| <a class="ui green button" href="{{.RepoLink}}/modelarts/inference-job/create">{{$.i18n.Tr "repo.modelarts.train_job.new_infer"}}</a> | |||
| {{else}} | |||
| <a class="ui disabled button" >{{$.i18n.Tr "repo.modelarts.train_job.new_infer"}}</a> | |||
| {{end}} | |||
| </div> | |||
| </div> | |||
| {{if eq 0 (len .Tasks)}} | |||
| <div class="ui placeholder segment bgtask-none"> | |||
| <div class="ui icon header bgtask-header-pic"></div> | |||
| <div class="bgtask-content-header">未创建过推理任务</div> | |||
| <div class="bgtask-content"> | |||
| {{if $.RepoIsEmpty}} | |||
| <div class="bgtask-content-txt">代码版本:您还没有初始化代码仓库,请先<a href="{{.RepoLink}}">创建代码版本;</a></div> | |||
| {{end}} | |||
| {{if eq 0 $.MODEL_COUNT}} | |||
| <div class="bgtask-content-txt">模型文件:您还没有模型文件,请先通过<a href="{{.RepoLink}}/modelarts/train-job">训练任务</a>产生并 <a href="{{.RepoLink}}/modelmanage/show_model">导出模型</a> ;</div> | |||
| {{end}} | |||
| <div class="bgtask-content-txt">数据集:云脑1提供 CPU / GPU 资源,云脑2提供 Ascend NPU 资源,调试使用的数据集也需要上传到对应的环境;</div> | |||
| <div class="bgtask-content-txt">使用说明:可以参考启智AI协作平台<a href="https://git.openi.org.cn/zeizei/OpenI_Learning">小白训练营课程。</a></div> | |||
| </div> | |||
| </div> | |||
| {{else}} | |||
| <!-- 中下列表展示区 --> | |||
| <div class="ui grid"> | |||
| <div class="row"> | |||
| <div class="ui sixteen wide column"> | |||
| <!-- 任务展示 --> | |||
| <div class="dataset list"> | |||
| <!-- 表头 --> | |||
| <div class="ui grid stackable" style="background: #f0f0f0;;"> | |||
| <div class="row"> | |||
| <div class="three wide column padding0"> | |||
| <span style="margin:0 6px">{{$.i18n.Tr "repo.cloudbrain_task"}}</span> | |||
| </div> | |||
| <div class="three wide column text center padding0"> | |||
| <span style="margin:0 6px">{{$.i18n.Tr "repo.modelarts.infer_job.model_version"}}</span> | |||
| </div> | |||
| <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> | |||
| </div> | |||
| <!-- <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> | |||
| </div> | |||
| <div class="three wide column text center padding0"> | |||
| <span>{{$.i18n.Tr "repo.cloudbrain_operate"}}</span> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| {{range .Tasks}} | |||
| <div class="ui grid stackable item"> | |||
| <div class="row"> | |||
| <!-- 任务名 --> | |||
| <div class="three wide column padding0"> | |||
| <a class="title" href="{{$.Link}}/{{.JobID}}" title="{{.JobName}}" style="font-size: 14px;"> | |||
| <span class="fitted" style="width: 90%;vertical-align: middle;">{{.JobName}}</span> | |||
| </a> | |||
| </div> | |||
| <!-- 模型版本 --> | |||
| <!-- href="{{$.RepoLink}}/modelmanage/show_model_info?name={{.ModelName}}" --> | |||
| <div class="three wide column text center padding0"> | |||
| <a id="{{.JobName}}" href="javascript:void(0);" data-variation="inverted" data-position="top center" data-content="{{$.i18n.Tr "repo.modelarts.infer_job.tooltip"}}" onclick="getModelInfo({{.ModelName}},{{.ModelVersion}},{{.JobName}})">{{.ModelName}} </a> <span style="font-size: 12px;">{{.ModelVersion}} </span> | |||
| </div> | |||
| <!-- 任务状态 --> | |||
| <div class="two wide column text center padding0" > | |||
| <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 text center padding0"> | |||
| <span style="font-size: 12px;" id="duration-{{.JobID}}">{{.TrainJobDuration}}</span> | |||
| </div> | |||
| <!-- 计算资源 --> | |||
| <!-- <div class="two wide column text center padding0"> | |||
| <span style="font-size: 12px;">{{.ComputeResource}}</span> | |||
| </div> --> | |||
| <!-- 创建者 --> | |||
| <div class="one wide column text center padding0"> | |||
| {{if .User.Name}} | |||
| <a href="{{AppSubUrl}}/{{.User.Name}}" title="{{.User.Name}}"><img class="ui avatar image" src="{{.User.RelAvatarLink}}"></a> | |||
| {{else}} | |||
| <a title="Ghost"><img class="ui avatar image" src="{{AppSubUrl}}/user/avatar/Ghost/-1"></a> | |||
| {{end}} | |||
| </div> | |||
| <div class="three wide column text center padding0"> | |||
| <!-- 停止任务 --> | |||
| <div class="ui compact buttons"> | |||
| {{$.CsrfTokenHtml}} | |||
| {{if .CanDel}} | |||
| <a style="padding: 0.5rem 1rem;" id="{{.JobID}}-stop" class="ui basic {{if eq .Status "KILLED" "FAILED" "START_FAILED" "KILLING" "COMPLETED"}}disabled {{else}} blue {{end}}button" onclick="stopVersion({{.VersionName}},{{.JobID}})"> | |||
| {{$.i18n.Tr "repo.stop"}} | |||
| </a> | |||
| {{else}} | |||
| <a style="padding: 0.5rem 1rem;" id="{{.JobID}}-stop" class="ui basic disabled button"> | |||
| {{$.i18n.Tr "repo.stop"}} | |||
| </a> | |||
| {{end}} | |||
| </div> | |||
| <!-- 下载 --> | |||
| <div class="ui compact buttons"> | |||
| {{$.CsrfTokenHtml}} | |||
| {{if .CanModify}} | |||
| <a style="padding: 0.5rem 1rem;margin-left:0.2rem" id="model-download-{{.JobID}}" href="{{$.RepoLink}}/modelarts/inference-job/{{.JobID}}/downloadall?version_name={{.VersionName}}" class="ui basic blue button" style="border-radius: .28571429rem;"> | |||
| {{$.i18n.Tr "repo.model_download"}} | |||
| </a> | |||
| {{else}} | |||
| <a style="padding: 0.5rem 1rem;margin-left:0.2rem" class="ui basic button disabled" style="border-radius: .28571429rem;"> | |||
| {{$.i18n.Tr "repo.model_download"}} | |||
| </a> | |||
| {{end}} | |||
| </div> | |||
| <!-- 删除任务 --> | |||
| <div class="ui compact buttons"> | |||
| {{$.CsrfTokenHtml}} | |||
| {{if .CanDel}} | |||
| <a style="padding: 0.5rem 1rem;margin-left:0.2rem" id="model-delete-{{.JobID}}" class="ui basic blue button" onclick="assertDelete(this,{{.VersionName}},{{.JobID}})" style="border-radius: .28571429rem;"> | |||
| {{$.i18n.Tr "repo.delete"}} | |||
| </a> | |||
| {{else}} | |||
| <a style="padding: 0.5rem 1rem;margin-left:0.2rem" class="ui basic button disabled" style="border-radius: .28571429rem;"> | |||
| {{$.i18n.Tr "repo.delete"}} | |||
| </a> | |||
| {{end}} | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| {{end}} {{template "base/paginate" .}} | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| {{end}} | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </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> | |||
| {{template "base/footer" .}} | |||
| <script> | |||
| // 加载任务状态 | |||
| var timeid = window.setInterval(loadJobStatus, 15000); | |||
| $(document).ready(loadJobStatus); | |||
| function loadJobStatus() { | |||
| $(".job-status").each((index, job) => { | |||
| const jobID = job.dataset.jobid | |||
| const repoPath = job.dataset.repopath | |||
| const versionname = job.dataset.version | |||
| const status_text = $(`#${jobID}-text`).text() | |||
| const finalState = ['IMAGE_FAILED','SUBMIT_FAILED','DELETE_FAILED','KILLED','COMPLETED','FAILED','CANCELED','LOST','START_FAILED','SUBMIT_MODEL_FAILED','DEPLOY_SERVICE_FAILED','CHECK_FAILED'] | |||
| if(finalState.includes(status_text)){ | |||
| return | |||
| } | |||
| $.get(`/api/v1/repos/${repoPath}/modelarts/inference-job/${jobID}?version_name=${versionname}`, (data) => { | |||
| const jobID = data.JobID | |||
| const status = data.JobStatus | |||
| const duration = data.JobDuration | |||
| $('#duration-'+jobID).text(duration) | |||
| if (status != job.textContent.trim()) { | |||
| $('#' + jobID+'-icon').removeClass().addClass(status) | |||
| $('#' + jobID+ '-text').text(status) | |||
| finalState.includes(status) && $('#' + jobID + '-stop').removeClass('blue').addClass('disabled') | |||
| } | |||
| }).fail(function(err) { | |||
| console.log(err); | |||
| }); | |||
| }); | |||
| }; | |||
| function getModelInfo(ID,version,JobName){ | |||
| $.get("{{$.RepoLink}}/modelmanage/show_model_info_api?name="+ID,(data)=>{ | |||
| if(data.length===0){ | |||
| $(`#${JobName}`).popup('toggle') | |||
| }else{ | |||
| let versionData = data.filter((item)=>{ | |||
| return item.Version === version | |||
| }) | |||
| if(versionData.length==0){ | |||
| $(`#${JobName}`).popup('toggle') | |||
| } | |||
| else{ | |||
| location.href = "{{$.RepoLink}}/modelmanage/show_model_info?name="+ID | |||
| } | |||
| } | |||
| }) | |||
| } | |||
| function deleteVersion(version_name,jobID){ | |||
| const url = '/api/v1/repos/{{$.RepoRelPath}}/modelarts/inference-job/'+jobID+'/del_version' | |||
| $.post(url,{version_name:version_name},(data)=>{ | |||
| if(data.StatusOK===0){ | |||
| location.reload() | |||
| } | |||
| }).fail(function(err) { | |||
| console.log(err); | |||
| }); | |||
| } | |||
| function stopVersion(version_name,jobID){ | |||
| const url = '/api/v1/repos/{{$.RepoRelPath}}/modelarts/inference-job/'+jobID+'/stop_version' | |||
| $.post(url,{version_name:version_name},(data)=>{ | |||
| if(data.StatusOK===0){ | |||
| $('#'+version_name+'-stop').removeClass('blue') | |||
| $('#'+version_name+'-stop').addClass('disabled') | |||
| refreshStatus(version_name,jobID) | |||
| } | |||
| }).fail(function(err) { | |||
| console.log(err); | |||
| }); | |||
| } | |||
| function refreshStatus(version_name,jobID){ | |||
| const url = '/api/v1/repos/{{$.RepoRelPath}}/modelarts/inference-job/'+jobID+'?version_name='+version_name | |||
| $.get(url,(data)=>{ | |||
| $(`#${jobID}-icon`).attr("class",data.JobStatus) | |||
| // detail status and duration | |||
| $(`#${jobID}-text`).text(data.JobStatus) | |||
| }).fail(function(err) { | |||
| console.log(err); | |||
| }); | |||
| } | |||
| function assertDelete(obj,version_name,jobID) { | |||
| if (obj.style.color == "rgb(204, 204, 204)") { | |||
| return | |||
| } else { | |||
| // var delId = obj.parentNode.id | |||
| flag = 1; | |||
| $('.ui.basic.modal') | |||
| .modal({ | |||
| onDeny: function() { | |||
| flag = false | |||
| }, | |||
| onApprove: function() { | |||
| // document.getElementById(delId).submit() | |||
| deleteVersion(version_name,jobID) | |||
| flag = true | |||
| }, | |||
| onHidden: function() { | |||
| if (flag == false) { | |||
| $('.alert').html('您已取消操作').removeClass('alert-success').addClass('alert-danger').show().delay(1500).fadeOut(); | |||
| } | |||
| } | |||
| }) | |||
| .modal('show') | |||
| } | |||
| } | |||
| </script> | |||
| @@ -0,0 +1,477 @@ | |||
| {{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; | |||
| } | |||
| .width80{ | |||
| width: 80.7% !important; | |||
| } | |||
| .width84{ | |||
| width: 84% !important; | |||
| margin-left: 5.1rem !important; | |||
| } | |||
| .width35{ | |||
| width: 35.5% !important; | |||
| } | |||
| .nowrap { | |||
| white-space: nowrap !important; | |||
| } | |||
| </style> | |||
| <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_infer"}} | |||
| </h4> | |||
| <div class="ui attached segment"> | |||
| <!-- equal width --> | |||
| <form class="ui form" action="{{.Link}}" method="post"> | |||
| {{.CsrfTokenHtml}} | |||
| <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=""> | |||
| {{if $.model_version}} | |||
| <input type="hidden" id="ai_model_version" name="model_version" value="{{$.model_version}}"> | |||
| {{else}} | |||
| <input type="hidden" id="ai_model_version" name="model_version" value=""> | |||
| {{end}} | |||
| {{if $.label_names}} | |||
| <input type="hidden" id="ai_model_label" name="label_names" value="{{$.label_names}}"> | |||
| {{else}} | |||
| <input type="hidden" id="ai_model_label" name="label_names" value=""> | |||
| {{end}} | |||
| <h4 class="unite title ui header ">{{.i18n.Tr "repo.modelarts.train_job.basic_info"}}:</h4> | |||
| <div class="required unite min_title inline field"> | |||
| <label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.job_name"}}</label> | |||
| <input style="width: 60%;" name="job_name" id="trainjob_job_name" placeholder={{.i18n.Tr "repo.modelarts.train_job.job_name"}} value="{{.job_name}}" onkeyup="this.value=this.value.replace(/[, ]/g,'')" tabindex="3" autofocus required maxlength="64"> | |||
| <span class="tooltips" style="display: block;">请输入字母、数字、_和-,最长64个字符,且不能以中划线(-)结尾。</span> | |||
| </div> | |||
| <div class="unite min_title inline field"> | |||
| <label style="font-weight: normal;" 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, 255)"></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 inline min_title fields" style="width: 91.8%;"> | |||
| <div class="required eight wide field"> | |||
| <label style="font-weight: normal;white-space: nowrap;">{{.i18n.Tr "repo.modelarts.infer_job.select_model"}}</label> | |||
| <div class="ui fluid search selection dropdown loading " id="select_model"> | |||
| {{if $.ckpt_name}} | |||
| <input type="hidden" name="model_name" value="{{$.model_name}}" required> | |||
| <div class="text">{{$.model_name}}</div> | |||
| {{else}} | |||
| <input type="hidden" name="model_name" required> | |||
| <div class="text"></div> | |||
| {{end}} | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu" id="model_name"> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <div class="three wide field"> | |||
| <div class="ui fluid search selection dropdown" id="select_model_version"> | |||
| {{if $.ckpt_name}} | |||
| <input type="hidden" name="train_url" value="{{$.train_url}}" required> | |||
| <div class="text">{{$.model_version}}</div> | |||
| {{else}} | |||
| <input type="hidden" name="train_url" required> | |||
| <div class="text"></div> | |||
| {{end}} | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu" id="model_name_version"> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <div class="five wide field"> | |||
| <div class="ui fluid search selection dropdown" id="select_model_checkpoint"> | |||
| {{if $.ckpt_name}} | |||
| <input type="hidden" name="ckpt_name" value="{{$.ckpt_name}}" required> | |||
| <div class="text">{{$.ckpt_name}}</div> | |||
| {{else}} | |||
| <input type="hidden" name="ckpt_name" required> | |||
| <div class="text"></div> | |||
| {{end}} | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu" id="model_checkpoint"> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <span > | |||
| <i class="question circle icon" data-content="模型文件位置存储在环境变量ckpt_url中。" data-position="top center" data-variation="inverted mini"></i> | |||
| </span> | |||
| </div> | |||
| <!-- AI引擎 --> | |||
| <div class="required unite inline min_title fields" style="width: 90%;"> | |||
| <div class="required eight wide field"> | |||
| <label style="font-weight: normal;white-space: nowrap;">{{.i18n.Tr "repo.modelarts.train_job.AI_driver"}}</label> | |||
| <select class="ui fluid selection search dropdown" id="trainjob_engines"> | |||
| {{range .engines}} | |||
| <option value="{{.Value}}">{{.Value}}</option> | |||
| {{end}} | |||
| </select> | |||
| </div> | |||
| <div class="eight wide field" id="engine_name"> | |||
| <select class="ui fluid selection dropdown nowrap" id="trainjob_engine_versions" name="engine_id" style="white-space: nowrap;"> | |||
| {{range .engine_versions}} | |||
| <option name="engine_id" value="{{.ID}}">{{.Value}}</option> | |||
| {{end}} | |||
| </select> | |||
| </div> | |||
| </div> | |||
| <!-- 代码分支 --> | |||
| <div class="required unite min_title inline field"> | |||
| <label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.code_version"}}</label> | |||
| <select class="ui dropdown width35" id="code_version" name="branch_name"> | |||
| {{if .branch_name}} | |||
| <option name="branch_name" value="{{.branch_name}}">{{.branch_name}}</option> | |||
| {{range $k, $v :=.Branches}} | |||
| {{ if ne $v $.branch_name }} | |||
| <option name="branch_name" value="{{$v}}">{{$v}}</option> | |||
| {{end}} | |||
| {{end}} | |||
| {{else}} | |||
| <option name="branch_name" value="{{.branchName}}">{{.branchName}}</option> | |||
| {{range $k, $v :=.Branches}} | |||
| {{ if ne $v $.branchName }} | |||
| <option name="branch_name" value="{{$v}}">{{$v}}</option> | |||
| {{end}} | |||
| {{end}} | |||
| {{end}} | |||
| </select> | |||
| </div> | |||
| <!-- 数据集 --> | |||
| <div class="required unite min_title inline field"> | |||
| <label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.dataset"}}</label> | |||
| <select class="ui dropdown width35" id="trainjob_datasets" name="attachment" placeholder="选择数据集" required> | |||
| {{if $.uuid}} | |||
| <option name="attachment" value="{{$.uuid}}">{{$.datasetName}}</option> | |||
| {{end}} | |||
| {{range .attachments}} | |||
| <option value="">选择数据集</option> | |||
| <option name="attachment" value="{{.UUID}}">{{.Attachment.Name}}</option> | |||
| {{end}} | |||
| </select> | |||
| <span> | |||
| <i class="question circle icon" data-content="数据集位置存储在环境变量data_url中。" data-position="top center" data-variation="inverted mini"></i> | |||
| </span> | |||
| </div> | |||
| <!-- 启动文件 --> | |||
| <div class="inline unite min_title field required"> | |||
| <label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.start_file"}}</label> | |||
| {{if .bootFile}} | |||
| <input style="width: 35.5%;" name="boot_file" id="trainjob_boot_file" value="{{.bootFile}}" tabindex="3" autofocus required maxlength="255" > | |||
| {{else}} | |||
| <input style="width: 35.5%;" name="boot_file" id="trainjob_boot_file" value="" tabindex="3" autofocus required maxlength="255" > | |||
| {{end}} | |||
| <span > | |||
| <i class="question circle icon" data-content={{.i18n.Tr "repo.modelarts.infer_job.boot_file_helper"}} data-position="top center" data-variation="inverted mini"></i> | |||
| </span> | |||
| <a href="https://git.openi.org.cn/OpenIOSSG/MINIST_Example" target="_blank">查看样例</a> | |||
| </div> | |||
| <!-- 运行参数 --> | |||
| <div class="inline unite min_title field"> | |||
| <label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.run_parameter"}}</label> | |||
| <span id="add_run_para" style="margin-left: 0.5rem;cursor:pointer;color: rgba(3, 102, 214, 100);font-size: 14px;line-height: 26px;font-family: SourceHanSansSC-medium;"><i class="plus square outline icon"></i>{{.i18n.Tr "repo.modelarts.train_job.add_run_parameter"}}</span> | |||
| <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 width84" 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 style="font-weight: normal;">{{.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 unite min_title inline field" id="flaver_name"> | |||
| <label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.standard"}}</label> | |||
| <select class="ui dropdown width80" id="trainjob-flavor" name="flavor"> | |||
| {{range .flavor_infos}} | |||
| <option name="flavor" value="{{.Code}}">{{.Value}}</option> | |||
| {{end}} | |||
| </select> | |||
| </div> | |||
| <!-- 计算节点 --> | |||
| <div class="inline required unite min_title field"> | |||
| <label style="font-weight: normal;">{{.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="1" readonly> | |||
| </div> | |||
| <span class="tooltips" style="display: block;">推理输出路径存储在环境变量result_url中。</span> | |||
| </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> | |||
| const RepoLink = {{.RepoLink}} | |||
| const url_href = window.location.pathname.split('create')[0] | |||
| let nameMap,nameList | |||
| $(".ui.button").attr('href',url_href) | |||
| // 获取模型列表和模型名称对应的模型版本 | |||
| $.get(`${RepoLink}/modelmanage/query_model_for_predict`, (data) => { | |||
| nameMap = data.nameMap | |||
| nameList = data.nameList | |||
| let html = '' | |||
| nameList.forEach(element => { | |||
| html += `<div class="item" data-value=${element}>${element}</div>` | |||
| }); | |||
| if(nameList.length!==0){ | |||
| const initModelVersion = nameMap[nameList[0]][0] | |||
| const initTrainTaskInfo = JSON.parse(initModelVersion.TrainTaskInfo) | |||
| $('#model_name').append(html) | |||
| $("#select_model").dropdown('set text',nameList[0]) | |||
| $("#select_model").dropdown('set value',nameList[0],nameList[0]) | |||
| } | |||
| $('#select_model').removeClass("loading") | |||
| }) | |||
| // 根据选中的模型名称获取相应的模型版本 | |||
| $(function(){ | |||
| $('#select_model').dropdown({ | |||
| onChange: function(value, text, $selectedItem) { | |||
| $("#select_model_version").addClass("loading") | |||
| $('#model_name_version').empty() | |||
| let html = '' | |||
| nameMap[value].forEach(element => { | |||
| let {TrainTaskInfo} = element | |||
| TrainTaskInfo = JSON.parse(TrainTaskInfo) | |||
| html += `<div class="item" data-label="${element.Label}" data-id="${element.ID}" data-value="${TrainTaskInfo.TrainUrl}">${element.Version}</div>` | |||
| }); | |||
| $('#model_name_version').append(html) | |||
| $("#select_model_version").removeClass("loading") | |||
| const initVersionText = $('#model_name_version div.item:first-child').text() | |||
| const initVersionValue = $('#model_name_version div.item:first-child').data('value') | |||
| $("#select_model_version").dropdown('set text',initVersionText) | |||
| $("#select_model_version").dropdown('set value',initVersionValue,initVersionText,$('#model_name_version div.item:first-child')) | |||
| } | |||
| }) | |||
| }) | |||
| // 根据选中的模型版本获取相应的模型权重文件 | |||
| $(function(){ | |||
| $('#select_model_version').dropdown({ | |||
| onChange: function(value, text, $selectedItem) { | |||
| const dataID = $selectedItem[0].getAttribute("data-id") | |||
| const label = $selectedItem[0].getAttribute("data-label") | |||
| $("#select_model_checkpoint").addClass("loading") | |||
| $("#model_checkpoint").empty() | |||
| let html = '' | |||
| loadCheckpointList(dataID).then((res)=>{ | |||
| res.forEach(element => { | |||
| const ckptSuffix = element.FileName.split(".") | |||
| const loadCheckpointFile = ['ckpt','pb','h5','json','pkl','pth','t7'] | |||
| if(!element.IsDir && loadCheckpointFile.includes(ckptSuffix[ckptSuffix.length-1])){ | |||
| html += `<div class="item" data-value=${element.FileName}>${element.FileName}</div>` | |||
| } | |||
| }) | |||
| $('#model_checkpoint').append(html) | |||
| $("#select_model_checkpoint").removeClass("loading") | |||
| const initVersionText = $('#model_checkpoint div.item:first-child').text() | |||
| const initVersionValue = $('#model_checkpoint div.item:first-child').data('value') | |||
| $("#select_model_checkpoint").dropdown('set text',initVersionText) | |||
| $("#select_model_checkpoint").dropdown('set value',initVersionValue,initVersionText,$('#model_name_version div.item:first-child')) | |||
| }) | |||
| $("input#ai_model_version").val(text) | |||
| $("input#ai_model_label").val(label) | |||
| } | |||
| }) | |||
| }) | |||
| function loadCheckpointList(value){ | |||
| return new Promise((resolve,reject)=>{ | |||
| $.get(`${RepoLink}/modelmanage/query_modelfile_for_predict`,{ID:value}, (data) => { | |||
| resolve(data) | |||
| }) | |||
| }) | |||
| } | |||
| $('.question.circle.icon').hover(function(){ | |||
| $(this).popup('show') | |||
| }); | |||
| // 参数增加、删除、修改、保存 | |||
| function Add_parameter(i){ | |||
| value = '<div class="two fields width84" 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) | |||
| }) | |||
| }); | |||
| function send_run_para(){ | |||
| var run_parameters = [] | |||
| var msg = {} | |||
| $(".dynamic.field .two.fields").each(function(){ | |||
| var para_name = $(this).find('input[name=shipping_first-name]').val() | |||
| var para_value = $(this).find('input[name=shipping_last-name]').val() | |||
| run_parameters.push({"label": para_name, "value": para_value}) | |||
| }) | |||
| msg["parameter"] = run_parameters | |||
| msg = JSON.stringify(msg) | |||
| $('#store_run_para').val(msg) | |||
| } | |||
| function get_name(){ | |||
| let name1=$("#engine_name .text").text() | |||
| let name2=$("#flaver_name .text").text() | |||
| $("input#ai_engine_name").val(name1) | |||
| $("input#ai_flaver_name").val(name2) | |||
| } | |||
| function validate(){ | |||
| $('.ui.form') | |||
| .form({ | |||
| on: 'blur', | |||
| fields: { | |||
| boot_file: { | |||
| identifier : 'boot_file', | |||
| rules: [ | |||
| { | |||
| type: 'regExp[/.+\.py$/g]', | |||
| } | |||
| ] | |||
| }, | |||
| job_name:{ | |||
| identifier : 'job_name', | |||
| rules: [ | |||
| { | |||
| type: 'regExp[/^[a-zA-Z0-9-_]{1,64}[^-]$/]', | |||
| } | |||
| ] | |||
| }, | |||
| attachment:{ | |||
| identifier : 'attachment', | |||
| rules: [ | |||
| { | |||
| type: 'empty', | |||
| } | |||
| ] | |||
| }, | |||
| model_name:{ | |||
| identifier : 'model_name', | |||
| rules: [ | |||
| { | |||
| type: 'empty', | |||
| } | |||
| ] | |||
| }, | |||
| train_url:{ | |||
| identifier : 'train_url', | |||
| rules: [ | |||
| { | |||
| type: 'empty', | |||
| } | |||
| ] | |||
| }, | |||
| ckpt_name:{ | |||
| identifier : 'ckpt_name', | |||
| rules: [ | |||
| { | |||
| type: 'empty', | |||
| } | |||
| ] | |||
| } | |||
| }, | |||
| onSuccess: function(){ | |||
| document.getElementById("mask").style.display = "block" | |||
| }, | |||
| onFailure: function(e){ | |||
| return false; | |||
| } | |||
| }) | |||
| } | |||
| document.onreadystatechange = function() { | |||
| if (document.readyState === "complete") { | |||
| document.getElementById("mask").style.display = "none" | |||
| } | |||
| } | |||
| $('.ui.create_train_job.green.button').click(function(e) { | |||
| send_run_para() | |||
| get_name() | |||
| validate() | |||
| }) | |||
| </script> | |||
| @@ -0,0 +1,653 @@ | |||
| {{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 !important; | |||
| 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 { | |||
| width: 450px; | |||
| 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"> | |||
| {{template "repo/header" .}} | |||
| <div class="ui container"> | |||
| <h4 class="ui header" id="vertical-segment"> | |||
| <div class="ui breadcrumb"> | |||
| <a class="section" href="{{.RepoLink}}/debugjob?debugListType=all"> | |||
| {{.i18n.Tr "repo.cloudbrain"}} | |||
| </a> | |||
| <div class="divider"> / </div> | |||
| <a class="section" href="{{$.RepoLink}}/modelarts/inference-job"> | |||
| {{$.i18n.Tr "repo.modelarts.infer_job"}} | |||
| </a> | |||
| <div class="divider"> / </div> | |||
| <div class="active section">{{.jobName}}</div> | |||
| </div> | |||
| </h4> | |||
| {{with .task}} | |||
| <div class="content-pad" style="border: 1px solid #e2e2e2;margin-top: 24px;padding: 20px 60px 40px 60px;"> | |||
| <div class="ui pointing secondary menu" style="border-bottom: 1px solid rgba(34,36,38,.15);"> | |||
| <a class="active item" data-tab="first">{{$.i18n.Tr "repo.modelarts.train_job.config"}}</a> | |||
| <a class="item" data-tab="second" onclick="loadLog({{.VersionName}})">{{$.i18n.Tr "repo.modelarts.log"}}</a> | |||
| <a class="item" data-tab="third" onclick="loadModelFile({{.VersionName}},'','','init')">{{$.i18n.Tr "repo.model_download"}}</a> | |||
| </div> | |||
| <div class="ui tab active" data-tab="first"> | |||
| <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> | |||
| <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 .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.AI_driver"}} | |||
| </td> | |||
| <td class="ti-text-form-content"> | |||
| <div class="text-span text-span-w"> | |||
| {{.EngineName}} | |||
| </div> | |||
| </td> | |||
| </tr> | |||
| <tr class="ti-no-ng-animate"> | |||
| <td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||
| {{$.i18n.Tr "repo.model.manage.description"}} | |||
| </td> | |||
| <td class="ti-text-form-content"> | |||
| <div class="text-span text-span-w" id="{{.VersionName}}-desc" style="width: 380px;"> | |||
| {{if .Description}} | |||
| <span title="{{.Description}}">{{.Description}}</span> | |||
| {{else}} | |||
| <span>--</span> | |||
| {{end}} | |||
| </div> | |||
| </td> | |||
| </tr> | |||
| <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" id="{{.VersionName}}-creator"> | |||
| {{$.userName}} | |||
| </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.infer_job_model"}} | |||
| </td> | |||
| <td class="ti-text-form-content"> | |||
| <div class="text-span text-span-w"> | |||
| <span>{{.ModelName}}</span> | |||
| <span style="color: #8a8e99">{{$.i18n.Tr "repo.modelarts.version"}}:</span><span>{{.ModelVersion}}</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.infer_job_model_file"}} | |||
| </td> | |||
| <td class="ti-text-form-content"> | |||
| <div class="text-span text-span-w"> | |||
| {{.CkptName}} | |||
| </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.model_label"}} | |||
| </td> | |||
| <td class="ti-text-form-content"> | |||
| <div class="text-span text-span-w" id="{{.VersionName}}-labels"> | |||
| {{if .LabelName}} | |||
| {{range $.labelName}} | |||
| <a class="ui label" title="{{.}}">{{.}}</a> | |||
| {{end}} | |||
| {{else}} | |||
| <span>--</span> | |||
| {{end}} | |||
| </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.code_version"}} | |||
| </td> | |||
| <td class="ti-text-form-content"> | |||
| <div class="text-span text-span-w"> | |||
| {{.BranchName}} | |||
| </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_file"}} | |||
| </td> | |||
| <td class="ti-text-form-content"> | |||
| <div class="text-span text-span-w"> | |||
| {{.BootFile}} | |||
| </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.infer_dataset"}} | |||
| </td> | |||
| <td class="ti-text-form-content"> | |||
| <div class="text-span text-span-w"> | |||
| {{.DatasetName}} | |||
| </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.run_parameter"}} | |||
| </td> | |||
| <td class="ti-text-form-content"> | |||
| <div class="text-span text-span-w" title="{{.Parameters}}"> | |||
| {{if .Parameters}} | |||
| <span>{{.Parameters}}</span> | |||
| {{else}} | |||
| <span>--</span> | |||
| {{end}} | |||
| </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> | |||
| </tbody> | |||
| </table> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <div class="ui tab" data-tab="second"> | |||
| <div> | |||
| <div class="ui message message{{.VersionName}}" style="display: none;"> | |||
| <div id="header"></div> | |||
| </div> | |||
| <div class="ui attached log" onscroll="logScroll({{.VersionName}})" id="log{{.VersionName}}" style="height: 300px !important; overflow: auto;"> | |||
| <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"> | |||
| <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">result</div> | |||
| <div class="divider"> / </div> | |||
| </div> | |||
| <div id="dir_list{{.VersionName}}"> | |||
| </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> | |||
| {{template "base/footer" .}} | |||
| <script> | |||
| console.log({{.task}}) | |||
| $(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] | |||
| repoPath = urlArr.slice(-4)[0] | |||
| jobID = urlArr.slice(-1)[0] | |||
| }) | |||
| function loadLog(version_name){ | |||
| $.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/inference-job/${jobID}/log?version_name=${version_name}&lines=50&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 logScroll(version_name) { | |||
| let container = document.querySelector(`#log${version_name}`) | |||
| let scrollTop = container.scrollTop | |||
| let scrollHeight = container.scrollHeight | |||
| let clientHeight = container.clientHeight | |||
| let scrollLeft = container.scrollLeft | |||
| if((parseInt(scrollTop) + clientHeight == scrollHeight || parseInt(scrollTop) + clientHeight +1 == scrollHeight || parseInt(scrollTop) + clientHeight - 1 == scrollHeight) && (scrollLeft===0)){ | |||
| let end_line = $(`#log${version_name} input[name=end_line]`).val() | |||
| $.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/inference-job/${jobID}/log?version_name=${version_name}&base_line=${end_line}&lines=50&order=desc`, (data) => { | |||
| if (data.Lines == 0){ | |||
| $(`.message${version_name} #header`).text('您已翻阅至日志底部') | |||
| $(`.message${version_name}`).css('display', 'block') | |||
| setTimeout(function(){ | |||
| $(`.message${version_name}`).css('display', 'none') | |||
| }, 1000) | |||
| }else{ | |||
| if(end_line===data.EndLine){ | |||
| return | |||
| } | |||
| else{ | |||
| $(`#log${version_name} input[name=end_line]`).val(data.EndLine) | |||
| $(`#log${version_name}`).append('<pre>' + data.Content) | |||
| } | |||
| } | |||
| }).fail(function(err) { | |||
| console.log(err); | |||
| }); | |||
| } | |||
| if(scrollTop == 0 && scrollLeft==0){ | |||
| let start_line = $(`#log${version_name} input[name=start_line]`).val() | |||
| $.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/inference-job/${jobID}/log?version_name=${version_name}&base_line=${start_line}&lines=50&order=asc`, (data) => { | |||
| if (data.Lines == 0){ | |||
| $(`.message${version_name} #header`).text('您已翻阅至日志顶部') | |||
| $(`.message${version_name}`).css('display', 'block') | |||
| setTimeout(function(){ | |||
| $(`.message${version_name}`).css('display', 'none') | |||
| }, 1000) | |||
| }else{ | |||
| $(`#log${version_name} input[name=start_line]`).val(data.StartLine) //如果变动就改变所对应的值 | |||
| $(`#log${version_name}`).prepend('<pre>' + data.Content) | |||
| } | |||
| }).fail(function(err) { | |||
| console.log(err); | |||
| }); | |||
| } | |||
| } | |||
| function renderSize(value){ | |||
| if(null==value||value==''){ | |||
| return "0 Bytes"; | |||
| } | |||
| var unitArr = new Array("Bytes","KB","MB","GB","TB","PB","EB","ZB","YB"); | |||
| var index=0; | |||
| var srcsize = parseFloat(value); | |||
| index=Math.floor(Math.log(srcsize)/Math.log(1024)); | |||
| var size =srcsize/Math.pow(1024,index); | |||
| size=size.toFixed(0);//保留的小数位数 | |||
| return size+unitArr[index]; | |||
| } | |||
| function loadModelFile(version_name,parents,filename,init){ | |||
| parents = parents || '' | |||
| filename = filename || '' | |||
| init = init || '' | |||
| $.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/inference-job/${jobID}/result_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'>result</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}/result_download?version_name=${version_name}&file_name=${data.Dirs[i].FileName}&parent_dir=${data.Dirs[i].ParenDir}">` | |||
| 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'>" | |||
| if(data.Dirs[i].IsDir){ | |||
| html += "<span class='truncate has-emoji'></span>" | |||
| }else{ | |||
| 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) | |||
| } | |||
| </script> | |||
| @@ -48,7 +48,7 @@ | |||
| </div> | |||
| <div class="inline required field"> | |||
| <label>任务名称</label> | |||
| <input name="job_name" id="cloudbrain_job_name" placeholder="任务名称" value="{{.job_name}}" tabindex="3" autofocus required maxlength="254"> | |||
| <input name="job_name" id="cloudbrain_job_name" placeholder="任务名称" value="{{.job_name}}" tabindex="3" autofocus required maxlength="255" onkeyup="this.value=this.value.replace(/[, ]/g,'')"> | |||
| </div> | |||
| <div class="inline field"> | |||
| @@ -64,11 +64,11 @@ | |||
| <div class="inline required field"> | |||
| <label>工作环境</label> | |||
| <input name="de" id="cloudbrain_de" value="{{.env}}" tabindex="3" disabled autofocus required maxlength="254" readonly="readonly"> | |||
| <input name="de" id="cloudbrain_de" value="{{.env}}" tabindex="3" disabled autofocus required maxlength="255" readonly="readonly"> | |||
| </div> | |||
| <div class="inline required field"> | |||
| <label>类型</label> | |||
| <input name="job_type" id="cloudbrain_job_type" value="{{.notebook_type}}" tabindex="3" disabled autofocus required maxlength="254" readonly="readonly"> | |||
| <input name="job_type" id="cloudbrain_job_type" value="{{.notebook_type}}" tabindex="3" disabled autofocus required maxlength="255" readonly="readonly"> | |||
| </div> | |||
| <div class="inline required field"> | |||
| <label>规格</label> | |||
| @@ -81,11 +81,11 @@ | |||
| </div> | |||
| <div class="inline required field"> | |||
| <label>数据集存放路径</label> | |||
| <input name="dataset_path" id="cloudbrain_dataset_path" value="{{.dataset_path}}" tabindex="3" disabled autofocus required maxlength="254" readonly="readonly"> | |||
| <input name="dataset_path" id="cloudbrain_dataset_path" value="{{.dataset_path}}" tabindex="3" disabled autofocus required maxlength="255" readonly="readonly"> | |||
| </div> | |||
| <div class="inline field"> | |||
| <label>描述</label> | |||
| <input name="description" id="cloudbrain_description" tabindex="3" autofocus maxlength="254"> | |||
| <input name="description" id="cloudbrain_description" tabindex="3" autofocus maxlength="255"> | |||
| </div> | |||
| <div class="inline field"> | |||
| <label></label> | |||
| @@ -18,11 +18,11 @@ | |||
| <h4 class="ui dividing header">{{.i18n.Tr "repo.modelarts.train_job.basic_info"}}</h4> | |||
| <div class="required field"> | |||
| <label>{{.i18n.Tr "repo.modelarts.train_job.job_name"}}</label> | |||
| <input name="job_name" id="trainjob_job_name" placeholder={{.i18n.Tr "repo.modelarts.train_job.job_name"}} value="{{.job_name}}" tabindex="3" autofocus required maxlength="254" readonly=""> | |||
| <input name="job_name" id="trainjob_job_name" placeholder={{.i18n.Tr "repo.modelarts.train_job.job_name"}} value="{{.job_name}}" tabindex="3" autofocus required maxlength="255" readonly=""> | |||
| </div> | |||
| <div class="field"> | |||
| <label for="description">{{.i18n.Tr "repo.modelarts.train_job.description"}}</label> | |||
| <textarea id="description" maxlength="254" name="description" rows="2"></textarea> | |||
| <textarea id="description" maxlength="255" name="description" rows="2"></textarea> | |||
| </div> | |||
| <h4 class="ui dividing header">{{.i18n.Tr "repo.modelarts.train_job.parameter_setting"}}</h4> | |||
| <div class="required field"> | |||
| @@ -52,7 +52,7 @@ | |||
| </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="254"> | |||
| <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> | |||
| @@ -128,7 +128,7 @@ | |||
| </div> | |||
| <div class="inline required field"> | |||
| <label>{{.i18n.Tr "repo.modelarts.train_job.amount_of_compute_node"}}</label> | |||
| <input name="work_server_number" id="trainjob_work_server_num" tabindex="3" autofocus required maxlength="254"> | |||
| <input name="work_server_number" id="trainjob_work_server_num" tabindex="3" autofocus required maxlength="255"> | |||
| </div> | |||
| <div class="inline field"> | |||
| <button class="ui green button"> | |||
| @@ -34,6 +34,7 @@ | |||
| <div class="ui blue small menu compact selectcloudbrain"> | |||
| <a class="item" href="{{.RepoLink}}/debugjob?debugListType=all">{{$.i18n.Tr "repo.modelarts.notebook"}}</a> | |||
| <a class="active item" href="{{.RepoLink}}/modelarts/train-job">{{$.i18n.Tr "repo.modelarts.train_job"}}</a> | |||
| <a class="item" href="{{.RepoLink}}/modelarts/inference-job">{{$.i18n.Tr "repo.modelarts.infer_job"}}</a> | |||
| <a class="item" href="{{.RepoLink}}/cloudbrain/benchmark">{{$.i18n.Tr "repo.modelarts.evaluate_job"}}</a> | |||
| </div> | |||
| </div> | |||
| @@ -142,11 +143,11 @@ | |||
| <div class="ui compact buttons"> | |||
| {{$.CsrfTokenHtml}} | |||
| {{if .CanDel}} | |||
| <a style="padding: 0.5rem 1rem;" id="{{.VersionName}}-stop" class="ui basic {{if eq .Status "KILLED" "FAILED" "START_FAILED" "KILLING" "COMPLETED"}}disabled {{else}} blue {{end}}button" onclick="stopVersion({{.VersionName}},{{.JobID}})"> | |||
| <a style="padding: 0.5rem 1rem;" id="{{.JobID}}-stop" class="ui basic {{if eq .Status "KILLED" "FAILED" "START_FAILED" "KILLING" "COMPLETED"}}disabled {{else}} blue {{end}}button" onclick="stopVersion({{.VersionName}},{{.JobID}})"> | |||
| {{$.i18n.Tr "repo.stop"}} | |||
| </a> | |||
| {{else}} | |||
| <a style="padding: 0.5rem 1rem;" id="{{.VersionName}}-stop" class="ui basic disabled button"> | |||
| <a style="padding: 0.5rem 1rem;" id="{{.JobID}}-stop" class="ui basic disabled button"> | |||
| {{$.i18n.Tr "repo.stop"}} | |||
| </a> | |||
| {{end}} | |||
| @@ -263,7 +264,8 @@ | |||
| const repoPath = job.dataset.repopath | |||
| const versionname = job.dataset.version | |||
| const status_text = $(`#${jobID}-text`).text() | |||
| if(['IMAGE_FAILED','SUBMIT_FAILED','DELETE_FAILED','KILLED','COMPLETED','FAILED','CANCELED','LOST','START_FAILED'].includes(status_text)){ | |||
| const finalState = ['IMAGE_FAILED','SUBMIT_FAILED','DELETE_FAILED','KILLED','COMPLETED','FAILED','CANCELED','LOST','START_FAILED','SUBMIT_MODEL_FAILED','DEPLOY_SERVICE_FAILED','CHECK_FAILED'] | |||
| if(finalState.includes(status_text)){ | |||
| return | |||
| } | |||
| $.get(`/api/v1/repos/${repoPath}/modelarts/train-job/${jobID}?version_name=${versionname}`, (data) => { | |||
| @@ -274,6 +276,7 @@ | |||
| if (status != job.textContent.trim()) { | |||
| $('#' + jobID+'-icon').removeClass().addClass(status) | |||
| $('#' + jobID+ '-text').text(status) | |||
| finalState.includes(status) && $('#' + jobID + '-stop').removeClass('blue').addClass('disabled') | |||
| } | |||
| @@ -80,12 +80,13 @@ | |||
| <h4 class="unite title ui header ">{{.i18n.Tr "repo.modelarts.train_job.basic_info"}}:</h4> | |||
| <div class="required unite min_title inline field"> | |||
| <label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.job_name"}}</label> | |||
| <input style="width: 60%;" name="job_name" id="trainjob_job_name" placeholder={{.i18n.Tr "repo.modelarts.train_job.job_name"}} value="{{.job_name}}" tabindex="3" autofocus required maxlength="254"> | |||
| <input style="width: 60%;" name="job_name" id="trainjob_job_name" placeholder={{.i18n.Tr "repo.modelarts.train_job.job_name"}} value="{{.job_name}}" tabindex="3" onkeyup="this.value=this.value.replace(/[, ]/g,'')" autofocus required maxlength="64"> | |||
| <span class="tooltips" style="display: block;">请输入字母、数字、_和-,最长64个字符,且不能以中划线(-)结尾。</span> | |||
| </div> | |||
| <div class="unite min_title inline field"> | |||
| <label style="font-weight: normal;" for="description">{{.i18n.Tr "repo.modelarts.train_job.description"}} </label> | |||
| <textarea style="width: 80%;" id="description" name="description" rows="3" maxlength="254" 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, 255)"></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, 255)"></textarea> | |||
| </div> | |||
| <div class="ui divider"></div> | |||
| @@ -110,7 +111,6 @@ | |||
| {{end}} | |||
| {{end}} | |||
| {{end}} | |||
| </select> | |||
| </div> | |||
| @@ -140,9 +140,9 @@ | |||
| <div class="inline unite min_title field required"> | |||
| <label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.start_file"}}</label> | |||
| {{if .bootFile}} | |||
| <input style="width: 33.5%;" name="boot_file" id="trainjob_boot_file" value="{{.bootFile}}" tabindex="3" autofocus required maxlength="254" > | |||
| <input style="width: 33.5%;" name="boot_file" id="trainjob_boot_file" value="{{.bootFile}}" 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="254" > | |||
| <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> | |||
| @@ -226,7 +226,7 @@ | |||
| <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="254" 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> | |||
| </div> | |||
| @@ -312,7 +312,6 @@ | |||
| }) | |||
| }); | |||
| console.log(parameters) | |||
| $('.ui.parameter.modal') | |||
| .modal('hide'); | |||
| for(var i = 2; i < parameters.length; i++){ | |||
| @@ -379,65 +378,16 @@ | |||
| $('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之间,请您键入正确的值' | |||
| } | |||
| ] | |||
| } | |||
| }, | |||
| }) | |||
| function validate(){ | |||
| $('.ui.form') | |||
| .form({ | |||
| on: 'blur', | |||
| inline:true, | |||
| fields: { | |||
| boot_file: { | |||
| identifier : 'boot_file', | |||
| rules: [ | |||
| { | |||
| type: 'regExp[/.+\.py$/g]', | |||
| prompt : '启动文件必须为.py结尾' | |||
| } | |||
| ] | |||
| }, | |||
| @@ -445,8 +395,7 @@ | |||
| identifier : 'job_name', | |||
| rules: [ | |||
| { | |||
| type: 'regExp[/^[a-zA-Z0-9-_]{1,36}$/]', | |||
| prompt : '只包含大小写字母、数字、_和-,最长36个字符。' | |||
| type: 'regExp[/^[a-zA-Z0-9-_]{1,64}[^-]$/]', | |||
| } | |||
| ] | |||
| }, | |||
| @@ -455,7 +404,6 @@ | |||
| rules: [ | |||
| { | |||
| type: 'empty', | |||
| prompt : '选择一个数据集' | |||
| } | |||
| ] | |||
| @@ -465,7 +413,6 @@ | |||
| rules: [ | |||
| { | |||
| type : 'integer[1..25]', | |||
| prompt : '计算节点需要在1-25之间,请您键入正确的值' | |||
| } | |||
| ] | |||
| } | |||
| @@ -175,7 +175,7 @@ td, th { | |||
| <div class="ui container"> | |||
| <h4 class="ui header" id="vertical-segment"> | |||
| <div class="ui breadcrumb"> | |||
| <a class="section" href="{{.RepoLink}}/cloudbrain"> | |||
| <a class="section" href="{{.RepoLink}}/debugjob?debugListType=all"> | |||
| {{.i18n.Tr "repo.cloudbrain"}} | |||
| </a> | |||
| <div class="divider"> / </div> | |||
| @@ -196,25 +196,25 @@ td, th { | |||
| <span> | |||
| <div style="float: right;"> | |||
| {{$.CsrfTokenHtml}} | |||
| {{if and (.CanModify) (eq .Status "COMPLETED")}} | |||
| <a class="ti-action-menu-item" onclick="showcreate({{.}})">{{$.i18n.Tr "repo.modelarts.create_model"}}</a> | |||
| {{if and (.CanModify) (eq .Status "COMPLETED") ($.Permission.CanWrite $.UnitTypeModelManage) }} | |||
| <a class="ti-action-menu-item" id="{{.VersionName}}-create-model" onclick="showcreate({{.}})">{{$.i18n.Tr "repo.modelarts.create_model"}}</a> | |||
| {{else}} | |||
| <a class="ti-action-menu-item disabled">{{$.i18n.Tr "repo.modelarts.create_model"}}</a> | |||
| <a class="ti-action-menu-item disabled" id="{{.VersionName}}-create-model" onclick="showcreate({{.}})">{{$.i18n.Tr "repo.modelarts.create_model"}}</a> | |||
| {{end}} | |||
| {{$.CsrfTokenHtml}} | |||
| {{if .CanModify}} | |||
| <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 .CanDel}} | |||
| <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 .CanDel}} | |||
| <a class="ti-action-menu-item" onclick="deleteVersion({{.VersionName}})" style="color: #FF4D4F;">{{$.i18n.Tr "repo.delete"}}</a> | |||
| {{else}} | |||
| @@ -505,7 +505,7 @@ td, th { | |||
| </div> | |||
| <div class="inline field" style="margin-left: 75px;"> | |||
| <button onclick="createModel()" id="submitId" type="button" class="ui create_train_job green button" style="position: absolute;"> | |||
| <button onclick="createModel()" type="button" class="ui create_train_job green button" style="position: absolute;"> | |||
| {{.i18n.Tr "repo.model.manage.sava_model"}} | |||
| </button> | |||
| </div> | |||
| @@ -522,7 +522,6 @@ td, th { | |||
| <script> | |||
| $('.menu .item').tab() | |||
| $(document).ready(function(){ | |||
| $('.ui.accordion').accordion({selector:{trigger:'.icon'}}); | |||
| }); | |||
| @@ -614,7 +613,7 @@ td, th { | |||
| var srcsize = parseFloat(value); | |||
| index=Math.floor(Math.log(srcsize)/Math.log(1024)); | |||
| var size =srcsize/Math.pow(1024,index); | |||
| size=size.toFixed(2);//保留的小数位数 | |||
| size=size.toFixed(0);//保留的小数位数 | |||
| return size+unitArr[index]; | |||
| } | |||
| function loadJobStatus() { | |||
| @@ -644,6 +643,9 @@ td, th { | |||
| if(stopArray.includes(data.JobStatus)){ | |||
| $('#'+versionname+'-stop').addClass('disabled') | |||
| } | |||
| if(data.JobStatus==="COMPLETED"){ | |||
| $('#'+versionname+'-create-model').removeClass('disabled').addClass('blue') | |||
| } | |||
| }).fail(function(err) { | |||
| console.log(err); | |||
| }); | |||
| @@ -99,7 +99,7 @@ | |||
| <div class="unite min_title inline field"> | |||
| <label style="font-weight: normal;" for="description">{{.i18n.Tr "repo.modelarts.train_job.description"}} </label> | |||
| <textarea style="width: 80%;" id="description" value="{{.description}}" name="description" rows="3" maxlength="254" 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> | |||
| <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> | |||
| @@ -152,9 +152,9 @@ | |||
| <div class="inline unite min_title field required"> | |||
| <label style="font-weight: normal;">{{.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="254" > | |||
| <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="254" > | |||
| <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> | |||
| @@ -245,7 +245,7 @@ | |||
| <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="254" value="{{.work_server_number}}" 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="{{.work_server_number}}" readonly> | |||
| </div> | |||
| @@ -23,7 +23,7 @@ | |||
| <div class="column"></div> | |||
| <div class="column right aligned"> | |||
| <!-- --> | |||
| <a class="ui button {{if .Permission.CanWrite $.UnitTypeCloudBrain}} green {{else}} disabled {{end}}" onclick="showcreate(this)">{{$.i18n.Tr "repo.model.manage.import_new_model"}}</a> | |||
| <a class="ui button {{if .Permission.CanWrite $.UnitTypeModelManage}} green {{else}} disabled {{end}}" onclick="showcreate(this)">{{$.i18n.Tr "repo.model.manage.import_new_model"}}</a> | |||
| </div> | |||
| </div> | |||
| {{if eq $.MODEL_COUNT 0}} | |||
| @@ -38,6 +38,10 @@ | |||
| <div class="bgtask-content-txt">训练任务:您还没创建过训练任务,请先创建<a href="{{.RepoLink}}/modelarts/train-job">训练任务</a>。</div> | |||
| {{end}} | |||
| <div class="bgtask-content-txt">使用说明:可以参考启智AI协作平台<a href="https://git.openi.org.cn/zeizei/OpenI_Learning">小白训练营课程。</a></div> | |||
| </div> | |||
| <div style="display: none;"> | |||
| <div id="model_list"></div> | |||
| </div> | |||
| </div> | |||
| {{else}} | |||
| @@ -90,6 +94,7 @@ | |||
| </div> | |||
| <div class="content content-padding"> | |||
| <form id="formId" method="POST" class="ui form"> | |||
| <input type="hidden" name="initModel" value="{{$.MODEL_COUNT}}"> | |||
| <div class="ui error message"> | |||
| <!-- <p>asdasdasd</p> --> | |||
| </div> | |||
| @@ -53,7 +53,7 @@ | |||
| </div> | |||
| <div class="inline field {{if .Err_Description}}error{{end}}"> | |||
| <label for="description">{{.i18n.Tr "repo.repo_desc"}}</label> | |||
| <textarea id="description" name="description" maxlength="254">{{.description}}</textarea> | |||
| <textarea id="description" name="description" maxlength="255">{{.description}}</textarea> | |||
| </div> | |||
| <div class="inline field"> | |||
| @@ -19,7 +19,7 @@ | |||
| {{if .PageIsEditRelease}} | |||
| <b>{{.tag_name}}</b><span class="at">@</span><strong>{{.tag_target}}</strong> | |||
| {{else}} | |||
| <input id="tag-name" name="tag_name" value="{{.tag_name}}" placeholder="{{.i18n.Tr "repo.release.tag_name"}}" autofocus required maxlength="254"> | |||
| <input id="tag-name" name="tag_name" value="{{.tag_name}}" placeholder="{{.i18n.Tr "repo.release.tag_name"}}" autofocus required maxlength="255"> | |||
| <span class="at">@</span> | |||
| <div class="ui selection dropdown"> | |||
| <input type="hidden" name="tag_target" value="{{.tag_target}}"/> | |||
| @@ -42,7 +42,7 @@ | |||
| <div class="eleven wide column"> | |||
| <div class="field {{if .Err_Title}}error{{end}}"> | |||
| <label>{{.i18n.Tr "repo.release.title"}}</label> | |||
| <input name="title" placeholder="{{.i18n.Tr "repo.release.title"}}" value="{{.title}}" autofocus required maxlength="254"> | |||
| <input name="title" placeholder="{{.i18n.Tr "repo.release.title"}}" value="{{.title}}" autofocus required maxlength="255"> | |||
| </div> | |||
| <div class="field"> | |||
| <label>{{.i18n.Tr "repo.release.content"}}</label> | |||
| @@ -41,7 +41,7 @@ | |||
| {{end}} | |||
| <div class="field {{if .Err_Description}}error{{end}}"> | |||
| <label for="description">{{$.i18n.Tr "repo.repo_desc"}}</label> | |||
| <textarea id="description" name="description" rows="2" maxlength="254">{{.Repository.Description}}</textarea> | |||
| <textarea id="description" name="description" rows="2" maxlength="255">{{.Repository.Description}}</textarea> | |||
| </div> | |||
| <div class="field {{if .Err_Website}}error{{end}}"> | |||
| <label for="website">{{.i18n.Tr "repo.settings.site"}}</label> | |||
| @@ -152,7 +152,7 @@ | |||
| {{$isModelMangeEnabled := .Repository.UnitEnabled $.UnitTypeModelManage }} | |||
| <div class="inline field"> | |||
| <label>{{.i18n.Tr "repo.model_manager"}}</label> | |||
| <div class="ui checkbox"> | |||
| <div class="ui checkbox {{if ne $.MODEL_COUNT 0}}disabled{{end}}"> | |||
| <input class="enable-system" name="enable_model_manager" type="checkbox" {{if $isModelMangeEnabled}}checked{{end}}> | |||
| <label>{{.i18n.Tr "repo.settings.model_desc"}}</label> | |||
| </div> | |||
| @@ -160,7 +160,7 @@ | |||
| {{$isCloudBrainEnabled := .Repository.UnitEnabled $.UnitTypeCloudBrain }} | |||
| <div class="inline field"> | |||
| <label>{{.i18n.Tr "repo.cloudbrain"}}</label> | |||
| <div class="ui checkbox"> | |||
| <div class="ui checkbox {{if ne $.jobCount 0}}disabled{{end}}"> | |||
| <input class="enable-system" name="enable_cloud_brain" type="checkbox" {{if $isCloudBrainEnabled}}checked{{end}}> | |||
| <label>{{.i18n.Tr "repo.settings.cloudbrain_desc"}}</label> | |||
| </div> | |||
| @@ -625,4 +625,4 @@ | |||
| {{end}} | |||
| {{end}} | |||
| {{template "base/footer" .}} | |||
| {{template "base/footer" .}} | |||
| @@ -34,7 +34,7 @@ | |||
| </div> | |||
| <div class="field {{if .Err_Description}}error{{end}}"> | |||
| <label for="description">{{$.i18n.Tr "user.user_bio"}}</label> | |||
| <textarea id="description" name="description" rows="2" maxlength="254">{{.SignedUser.Description}}</textarea> | |||
| <textarea id="description" name="description" rows="2" maxlength="255">{{.SignedUser.Description}}</textarea> | |||
| </div> | |||
| <div class="field {{if .Err_Website}}error{{end}}"> | |||
| <label for="website">{{.i18n.Tr "settings.website"}}</label> | |||
| @@ -106,7 +106,7 @@ | |||
| <div class="space-around"> | |||
| <a :style="{visibility:!scope.row.Children ? 'visible':'hidden'}" :class="{'disabled':!scope.row.IsCanOper}" @click="showcreateVue(scope.row.Name,scope.row.Version,scope.row.Label)">创建新版本</a> | |||
| <a :href="loadhref+scope.row.ID" :class="{'disabled':!scope.row.IsCanOper}">下载</a> | |||
| <a :class="{'disabled':!scope.row.IsCanOper}" @click="deleteModel(scope.row.ID,scope.row.cName)">删除</a> | |||
| <a :class="{'disabled':!scope.row.IsCanDelete}" @click="deleteModel(scope.row.ID,scope.row.cName)">删除</a> | |||
| </div> | |||
| </template> | |||
| @@ -263,8 +263,10 @@ export default { | |||
| let cName = $("input[name='Name']").val() | |||
| let version = $("input[name='Version']").val() | |||
| let data = $("#formId").serialize() | |||
| const initModel = $("input[name='initModel']").val() | |||
| let url_href = version === '0.0.1' ? context.url_create_newModel : context.url_create_newVersion | |||
| $("#mask").css({"display":"block","z-index":"9999"}) | |||
| $.ajax({ | |||
| url:url_href, | |||
| type:'POST', | |||
| @@ -273,6 +275,9 @@ export default { | |||
| // context.loadrefresh1(row) | |||
| context.getModelList() | |||
| $('.ui.modal.second').modal('hide') | |||
| if(initModel==='0'){ | |||
| location.reload() | |||
| } | |||
| }, | |||
| error: function(xhr){ | |||
| // 隐藏 loading | |||
| @@ -360,6 +365,9 @@ export default { | |||
| this.tableData[i].hasChildren = res.data.data[i].VersionCount===1 ? false : true | |||
| } | |||
| this.totalNum = res.data.count | |||
| // if(res.data.count===1 && res.data.data[0].VersionCount===1){ | |||
| // location.reload() | |||
| // } | |||
| }) | |||
| }catch (e) { | |||
| console.log(e) | |||
| @@ -4128,7 +4128,7 @@ function initDropDown() { | |||
| } | |||
| //云脑提示 | |||
| $('.question.circle.icon').hover(function(){ | |||
| $('.question.circle.icon.cloudbrain-question').hover(function(){ | |||
| $(this).popup('show') | |||
| $('.ui.popup.mini.top.center').css({"border-color":'rgba(50, 145, 248, 100)',"color":"rgba(3, 102, 214, 100)","border-radius":"5px","border-shadow":"none"}) | |||
| }); | |||