@@ -30,7 +30,6 @@ const ( | |||
JobTypeSnn4imagenet JobType = "SNN4IMAGENET" | |||
JobTypeBrainScore JobType = "BRAINSCORE" | |||
JobTypeTrain JobType = "TRAIN" | |||
JobVersionName JobType = "V0001" | |||
ModelArtsCreateQueue ModelArtsJobStatus = "CREATE_QUEUING" //免费资源创建排队中 | |||
ModelArtsCreating ModelArtsJobStatus = "CREATING" //创建中 | |||
@@ -63,35 +62,36 @@ type Cloudbrain struct { | |||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` | |||
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` | |||
Duration int64 `xorm:"INDEX duration"` | |||
TrainJobDuration string | |||
DeletedAt time.Time `xorm:"deleted"` | |||
CanDebug bool `xorm:"-"` | |||
CanDel bool `xorm:"-"` | |||
Type int `xorm:"INDEX DEFAULT 0"` | |||
TrainJobDuration string `xorm:"INDEX DEFAULT '00:00:00'"` | |||
DeletedAt time.Time `xorm:"deleted"` | |||
CanDebug bool `xorm:"-"` | |||
CanDel bool `xorm:"-"` | |||
Type int `xorm:"INDEX DEFAULT 0"` | |||
VersionID int64 `xorm:"INDEX DEFAULT 0"` | |||
VersionName string `xorm:"INDEX"` | |||
Uuid string | |||
Uuid string //数据集id | |||
DatasetName string | |||
VersionCount int `xorm:"INDEX DEFAULT 1"` | |||
IsLatestVersion string | |||
CommitID string | |||
FatherVersionName string | |||
ComputeResource string | |||
EngineID int64 | |||
TrainUrl string | |||
BranchName string | |||
Parameters string | |||
BootFile string | |||
DataUrl string | |||
LogUrl string | |||
PreVersionId int64 | |||
FlavorCode string | |||
Description string | |||
WorkServerNumber int | |||
FlavorName string | |||
EngineName string | |||
VersionCount int `xorm:"INDEX DEFAULT 1"` //任务的当前版本数量,不包括删除的 | |||
IsLatestVersion string //是否是最新版本,1是,0否 | |||
CommitID string //提交的仓库代码id | |||
FatherVersionName string //父版本名称 | |||
ComputeResource string //计算资源,例如npu | |||
EngineID int64 //引擎id | |||
TrainUrl string //输出的obs路径 | |||
BranchName string //分支名称 | |||
Parameters string //传给modelarts的param参数 | |||
BootFile string //启动文件 | |||
DataUrl string //数据集的obs路径 | |||
LogUrl string //日志输出的obs路径 | |||
PreVersionId int64 //父版本的版本id | |||
FlavorCode string //modelarts上的规格id | |||
Description string | |||
WorkServerNumber int //节点数 | |||
FlavorName string //规格名称 | |||
EngineName string //引擎名称 | |||
TotalVersionCount int //任务的所有版本数量,包括删除的 | |||
User *User `xorm:"-"` | |||
Repo *Repository `xorm:"-"` | |||
@@ -1112,9 +1112,9 @@ func SetTrainJobStatusByJobID(jobID string, status string, duration int64, train | |||
return | |||
} | |||
func SetVersionCountAndLatestVersionByJobIDAndVersionName(jobID string, versionName string, versionCount int, isLatestVersion string) (err error) { | |||
cb := &Cloudbrain{JobID: jobID, VersionName: versionName, VersionCount: versionCount, IsLatestVersion: isLatestVersion} | |||
_, err = x.Cols("version_Count", "is_latest_version").Where("cloudbrain.job_id=? AND cloudbrain.version_name=?", jobID, versionName).Update(cb) | |||
func SetVersionCountAndLatestVersionByJobIDAndVersionName(jobID string, versionName string, versionCount int, isLatestVersion string, totalVersionCount int) (err error) { | |||
cb := &Cloudbrain{JobID: jobID, VersionName: versionName, VersionCount: versionCount, IsLatestVersion: isLatestVersion, TotalVersionCount: totalVersionCount} | |||
_, err = x.Cols("version_Count", "is_latest_version", "total_version_count").Where("cloudbrain.job_id=? AND cloudbrain.version_name=?", jobID, versionName).Update(cb) | |||
return | |||
} | |||
@@ -1124,8 +1124,8 @@ func UpdateJob(job *Cloudbrain) error { | |||
func updateJob(e Engine, job *Cloudbrain) error { | |||
var sess *xorm.Session | |||
sess = e.Where("job_id = ?", job.JobID) | |||
_, err := sess.Cols("status", "container_id", "container_ip").Update(job) | |||
sess = e.Where("job_id = ? AND version_name=?", job.JobID, job.VersionName) | |||
_, err := sess.Cols("status", "train_job_duration", "container_id", "container_ip").Update(job) | |||
return err | |||
} | |||
@@ -1149,6 +1149,15 @@ func deleteJob(e Engine, job *Cloudbrain) error { | |||
return err | |||
} | |||
func DeleteJobVersion(job *Cloudbrain) error { | |||
return deleteJobVersion(x, job) | |||
} | |||
func deleteJobVersion(e Engine, job *Cloudbrain) error { | |||
_, err := e.ID(job.ID).Delete(job) | |||
return err | |||
} | |||
func GetCloudbrainByName(jobName string) (*Cloudbrain, error) { | |||
cb := &Cloudbrain{JobName: jobName} | |||
return getRepoCloudBrain(cb) | |||
@@ -35,24 +35,24 @@ const ( | |||
// "{\"code\":\"modelarts.bm.910.arm.public.4\",\"value\":\"Ascend : 4 * Ascend 910 CPU:96 核 1024GiB\"}," + | |||
// "{\"code\":\"modelarts.bm.910.arm.public.1\",\"value\":\"Ascend : 1 * Ascend 910 CPU:24 核 256GiB\"}" + | |||
// "]}" | |||
CodePath = "/code/" | |||
OutputPath = "/output/" | |||
LogPath = "/log/" | |||
JobPath = "/job/" | |||
OrderDesc = "desc" //向下查询 | |||
OrderAsc = "asc" //向上查询 | |||
Lines = 20 | |||
TrainUrl = "train_url" | |||
DataUrl = "data_url" | |||
PerPage = 10 | |||
IsLatestVersion = "1" | |||
NotLatestVersion = "0" | |||
ComputeResource = "NPU" | |||
InitFatherVersionName = "V0001" | |||
VersionCount = 1 | |||
SortByCreateTime = "create_time" | |||
ConfigTypeCustom = "custom" | |||
CodePath = "/code/" | |||
OutputPath = "/output/" | |||
LogPath = "/log/" | |||
JobPath = "/job/" | |||
OrderDesc = "desc" //向下查询 | |||
OrderAsc = "asc" //向上查询 | |||
Lines = 500 | |||
TrainUrl = "train_url" | |||
DataUrl = "data_url" | |||
PerPage = 10 | |||
IsLatestVersion = "1" | |||
NotLatestVersion = "0" | |||
ComputeResource = "NPU" | |||
VersionCount = 1 | |||
SortByCreateTime = "create_time" | |||
ConfigTypeCustom = "custom" | |||
TotalVersionCount = 1 | |||
) | |||
var ( | |||
@@ -83,29 +83,32 @@ type GenerateTrainJobReq struct { | |||
FlavorName string | |||
VersionCount int | |||
EngineName string | |||
TotalVersionCount int | |||
} | |||
type GenerateTrainJobVersionReq struct { | |||
JobName string | |||
Uuid string | |||
Description string | |||
CodeObsPath string | |||
BootFile string | |||
BootFileUrl string | |||
DataUrl string | |||
TrainUrl string | |||
FlavorCode string | |||
LogUrl string | |||
PoolID string | |||
WorkServerNumber int | |||
EngineID int64 | |||
Parameters []models.Parameter | |||
Params string | |||
PreVersionId int64 | |||
CommitID string | |||
BranchName string | |||
FlavorName string | |||
EngineName string | |||
JobName string | |||
Uuid string | |||
Description string | |||
CodeObsPath string | |||
BootFile string | |||
BootFileUrl string | |||
DataUrl string | |||
TrainUrl string | |||
FlavorCode string | |||
LogUrl string | |||
PoolID string | |||
WorkServerNumber int | |||
EngineID int64 | |||
Parameters []models.Parameter | |||
Params string | |||
PreVersionId int64 | |||
CommitID string | |||
BranchName string | |||
FlavorName string | |||
EngineName string | |||
FatherVersionName string | |||
TotalVersionCount int | |||
} | |||
type VersionInfo struct { | |||
@@ -255,22 +258,22 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error | |||
} | |||
err = models.CreateCloudbrain(&models.Cloudbrain{ | |||
Status: TransTrainJobStatus(jobResult.Status), | |||
UserID: ctx.User.ID, | |||
RepoID: ctx.Repo.Repository.ID, | |||
JobID: strconv.FormatInt(jobResult.JobID, 10), | |||
JobName: req.JobName, | |||
JobType: string(models.JobTypeTrain), | |||
Type: models.TypeCloudBrainTwo, | |||
VersionID: jobResult.VersionID, | |||
VersionName: jobResult.VersionName, | |||
Uuid: req.Uuid, | |||
DatasetName: attach.Name, | |||
CommitID: req.CommitID, | |||
IsLatestVersion: req.IsLatestVersion, | |||
ComputeResource: ComputeResource, | |||
EngineID: req.EngineID, | |||
FatherVersionName: req.FatherVersionName, | |||
Status: TransTrainJobStatus(jobResult.Status), | |||
UserID: ctx.User.ID, | |||
RepoID: ctx.Repo.Repository.ID, | |||
JobID: strconv.FormatInt(jobResult.JobID, 10), | |||
JobName: req.JobName, | |||
JobType: string(models.JobTypeTrain), | |||
Type: models.TypeCloudBrainTwo, | |||
VersionID: jobResult.VersionID, | |||
VersionName: jobResult.VersionName, | |||
Uuid: req.Uuid, | |||
DatasetName: attach.Name, | |||
CommitID: req.CommitID, | |||
IsLatestVersion: req.IsLatestVersion, | |||
ComputeResource: ComputeResource, | |||
EngineID: req.EngineID, | |||
// FatherVersionName: req.FatherVersionName, | |||
TrainUrl: req.TrainUrl, | |||
BranchName: req.BranchName, | |||
Parameters: req.Params, | |||
@@ -283,6 +286,7 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error | |||
FlavorName: req.FlavorName, | |||
EngineName: req.EngineName, | |||
VersionCount: req.VersionCount, | |||
TotalVersionCount: req.TotalVersionCount, | |||
}) | |||
if err != nil { | |||
@@ -293,7 +297,7 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error | |||
return nil | |||
} | |||
func GenerateTrainJobVersion(ctx *context.Context, req *GenerateTrainJobVersionReq, jobId string, fatherVersionName string) (err error) { | |||
func GenerateTrainJobVersion(ctx *context.Context, req *GenerateTrainJobVersionReq, jobId string) (err error) { | |||
jobResult, err := createTrainJobVersion(models.CreateTrainJobVersionParams{ | |||
Description: req.Description, | |||
Config: models.TrainJobVersionConfig{ | |||
@@ -336,7 +340,7 @@ func GenerateTrainJobVersion(ctx *context.Context, req *GenerateTrainJobVersionR | |||
Uuid: req.Uuid, | |||
DatasetName: attach.Name, | |||
CommitID: req.CommitID, | |||
FatherVersionName: fatherVersionName, | |||
FatherVersionName: req.FatherVersionName, | |||
ComputeResource: ComputeResource, | |||
EngineID: req.EngineID, | |||
TrainUrl: req.TrainUrl, | |||
@@ -351,6 +355,7 @@ func GenerateTrainJobVersion(ctx *context.Context, req *GenerateTrainJobVersionR | |||
WorkServerNumber: req.WorkServerNumber, | |||
FlavorName: req.FlavorName, | |||
EngineName: req.EngineName, | |||
TotalVersionCount: req.TotalVersionCount, | |||
}) | |||
if err != nil { | |||
log.Error("CreateCloudbrain(%s) failed:%v", req.JobName, err.Error()) | |||
@@ -383,14 +388,14 @@ func GenerateTrainJobVersion(ctx *context.Context, req *GenerateTrainJobVersionR | |||
ctx.ServerError("GetCloudbrainByJobIDAndIsLatestVersion faild:", err) | |||
return err | |||
} | |||
err = models.SetVersionCountAndLatestVersionByJobIDAndVersionName(strconv.FormatInt(jobResult.JobID, 10), latestTask.VersionName, VersionListCount, NotLatestVersion) | |||
err = models.SetVersionCountAndLatestVersionByJobIDAndVersionName(strconv.FormatInt(jobResult.JobID, 10), latestTask.VersionName, VersionListCount, NotLatestVersion, req.TotalVersionCount) | |||
if err != nil { | |||
ctx.ServerError("UpdateJobVersionCount failed", err) | |||
return err | |||
} | |||
//将当前版本的isLatestVersion设置为"1"和任务数量更新 | |||
err = models.SetVersionCountAndLatestVersionByJobIDAndVersionName(strconv.FormatInt(jobResult.JobID, 10), jobResult.VersionName, VersionListCount, IsLatestVersion) | |||
//将当前版本的isLatestVersion设置为"1"和任务数量更新,任务数量包括当前版本数VersionCount和历史创建的总版本数TotalVersionCount | |||
err = models.SetVersionCountAndLatestVersionByJobIDAndVersionName(strconv.FormatInt(jobResult.JobID, 10), jobResult.VersionName, VersionListCount, IsLatestVersion, req.TotalVersionCount) | |||
if err != nil { | |||
ctx.ServerError("UpdateJobVersionCount failed", err) | |||
return err | |||
@@ -814,3 +814,44 @@ sendjob: | |||
return &result, nil | |||
} | |||
func DelTrainJobVersion(jobID string, versionID string) (*models.TrainJobResult, error) { | |||
checkSetting() | |||
client := getRestyClient() | |||
var result models.TrainJobResult | |||
retry := 0 | |||
sendjob: | |||
res, err := client.R(). | |||
SetAuthToken(TOKEN). | |||
SetResult(&result). | |||
Delete(HOST + "/v1/" + setting.ProjectID + urlTrainJob + "/" + jobID + "/versions/" + versionID) | |||
if err != nil { | |||
return &result, fmt.Errorf("resty DelTrainJobVersion: %v", err) | |||
} | |||
if res.StatusCode() == http.StatusUnauthorized && retry < 1 { | |||
retry++ | |||
_ = getToken() | |||
goto sendjob | |||
} | |||
if res.StatusCode() != http.StatusOK { | |||
var temp models.ErrorResult | |||
if err = json.Unmarshal([]byte(res.String()), &temp); err != nil { | |||
log.Error("json.Unmarshal failed(%s): %v", res.String(), err.Error()) | |||
return &result, fmt.Errorf("json.Unmarshal failed(%s): %v", res.String(), err.Error()) | |||
} | |||
log.Error("DelTrainJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||
return &result, fmt.Errorf("删除训练作业版本失败(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||
} | |||
if !result.IsSuccess { | |||
log.Error("DelTrainJob(%s) failed", jobID) | |||
return &result, fmt.Errorf("删除训练作业版本失败:%s", result.ErrorMsg) | |||
} | |||
return &result, nil | |||
} |
@@ -431,10 +431,10 @@ func GetObsListObject(jobName, parentDir string) ([]FileInfo, error) { | |||
} | |||
} | |||
func GetVersionObsListObject(jobName, parentDir string) ([]FileInfo, error) { | |||
func GetObsListObjectVersion(jobName, parentDir string, VersionOutputPath string) ([]FileInfo, error) { | |||
input := &obs.ListObjectsInput{} | |||
input.Bucket = setting.Bucket | |||
input.Prefix = strings.TrimPrefix(path.Join(setting.TrainJobModelPath, jobName, setting.OutPutPath, parentDir), "/") | |||
input.Prefix = strings.TrimPrefix(path.Join(setting.TrainJobModelPath, jobName, setting.OutPutPath, VersionOutputPath, parentDir), "/") | |||
strPrefix := strings.Split(input.Prefix, "/") | |||
output, err := ObsCli.ListObjects(input) | |||
fileInfos := make([]FileInfo, 0) | |||
@@ -478,6 +478,9 @@ func GetVersionObsListObject(jobName, parentDir string) ([]FileInfo, error) { | |||
} | |||
fileInfos = append(fileInfos, fileInfo) | |||
} | |||
sort.Slice(fileInfos, func(i, j int) bool { | |||
return fileInfos[i].ModTime > fileInfos[j].ModTime | |||
}) | |||
return fileInfos, err | |||
} else { | |||
if obsError, ok := err.(obs.ObsError); ok { | |||
@@ -558,6 +561,27 @@ func GetObsCreateSignedUrl(jobName, parentDir, fileName string) (string, error) | |||
// return output.SignedUrl, nil | |||
} | |||
func GetObsCreateVersionSignedUrl(jobName, parentDir, fileName string, VersionOutputPath string) (string, error) { | |||
input := &obs.CreateSignedUrlInput{} | |||
input.Bucket = setting.Bucket | |||
input.Key = strings.TrimPrefix(path.Join(setting.TrainJobModelPath, jobName, setting.OutPutPath, VersionOutputPath, parentDir, fileName), "/") | |||
input.Expires = 60 * 60 | |||
input.Method = obs.HttpMethodGet | |||
reqParams := make(map[string]string) | |||
fileName = url.QueryEscape(fileName) | |||
reqParams["response-content-disposition"] = "attachment; filename=\"" + fileName + "\"" | |||
input.QueryParams = reqParams | |||
output, err := ObsCli.CreateSignedUrl(input) | |||
if err != nil { | |||
log.Error("CreateSignedUrl failed:", err.Error()) | |||
return "", err | |||
} | |||
return output.SignedUrl, nil | |||
} | |||
func ObsGetPreSignedUrl(uuid, fileName string) (string, error) { | |||
input := &obs.CreateSignedUrlInput{} | |||
input.Method = obs.HttpMethodGet | |||
@@ -816,6 +816,10 @@ get_repo_info_error=Can not get the information of the repository. | |||
generate_statistic_file_error=Fail to generate file. | |||
repo_stat_inspect=ProjectAnalysis | |||
all=All | |||
modelarts.status=Status | |||
modelarts.createtime=CreateTime | |||
modelarts.version_nums = Version Nums | |||
modelarts.computing_resources=compute Resources | |||
modelarts.notebook=Debug Task | |||
modelarts.train_job=Train Task | |||
modelarts.train_job.new_debug= New Debug Task | |||
@@ -845,6 +849,7 @@ modelarts.train_job.start_file=Start File | |||
modelarts.train_job.boot_file_helper=The startup file is the entry file that your program executes, and it must be a file ending in .py | |||
modelarts.train_job.dataset=Dataset | |||
modelarts.code_version = Code Version | |||
modelarts.parents_version = Parents Version | |||
modelarts.train_job.run_parameter=Run Parameter | |||
modelarts.train_job.add_run_parameter=Add Run Parameter | |||
modelarts.train_job.parameter_name=Parameter Name | |||
@@ -819,6 +819,11 @@ get_repo_info_error=查询当前仓库信息失败。 | |||
generate_statistic_file_error=生成文件失败。 | |||
repo_stat_inspect=项目分析 | |||
all=所有 | |||
modelarts.status=状态 | |||
modelarts.createtime=创建时间 | |||
modelarts.version_nums=版本数 | |||
modelarts.computing_resources=计算资源 | |||
modelarts.notebook=调试任务 | |||
modelarts.train_job=训练任务 | |||
modelarts.train_job.new_debug=新建调试任务 | |||
@@ -848,7 +853,9 @@ modelarts.train_job.start_file=启动文件 | |||
modelarts.train_job.boot_file_helper=启动文件是您程序执行的入口文件,必须是以.py结尾的文件。 | |||
modelarts.train_job.boot_file_place=填写启动文件路径,默认为train.py | |||
modelarts.train_job.dataset=数据集 | |||
modelarts.code_version=代码版本 | |||
modelarts.code_version=代码分支 | |||
modelarts.parents_version=基于版本 | |||
modelarts.train_job.run_parameter=运行参数 | |||
modelarts.train_job.add_run_parameter=增加运行参数 | |||
modelarts.train_job.parameter_name=参数名 | |||
@@ -874,13 +874,12 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
}) | |||
m.Group("/train-job", func() { | |||
m.Group("/:jobid", func() { | |||
// m.Get("", repo.GetModelArtsTrainJob) | |||
m.Get("", repo.GetModelArtsTrainJobVersion) | |||
// m.Get("/log", repo.TrainJobGetLog) | |||
m.Get("/log", repo.TrainJobGetLog) | |||
// m.Group("/:version-name", func() { | |||
// m.Get("", repo.GetModelArtsTrainJobVersion) | |||
// }) | |||
m.Post("/del_version", repo.DelTrainJobVersion) | |||
m.Post("/stop_version", repo.StopTrainJobVersion) | |||
m.Get("/model_list", repo.ModelList) | |||
m.Get("/model_download", repo.ModelDownload) | |||
}) | |||
}) | |||
}, reqRepoReader(models.UnitTypeCloudBrain)) | |||
@@ -8,11 +8,14 @@ package repo | |||
import ( | |||
"net/http" | |||
"strconv" | |||
"strings" | |||
"code.gitea.io/gitea/models" | |||
"code.gitea.io/gitea/modules/context" | |||
"code.gitea.io/gitea/modules/log" | |||
"code.gitea.io/gitea/modules/modelarts" | |||
"code.gitea.io/gitea/modules/setting" | |||
"code.gitea.io/gitea/modules/storage" | |||
) | |||
func GetModelArtsNotebook(ctx *context.APIContext) { | |||
@@ -102,6 +105,14 @@ func GetModelArtsTrainJobVersion(ctx *context.APIContext) { | |||
job.Status = modelarts.TransTrainJobStatus(result.IntStatus) | |||
job.Duration = result.Duration | |||
job.TrainJobDuration = result.TrainJobDuration | |||
if result.Duration != 0 { | |||
job.TrainJobDuration = addZero(result.Duration/3600000) + ":" + addZero(result.Duration%3600000/60000) + ":" + addZero(result.Duration%60000/1000) | |||
} else { | |||
job.TrainJobDuration = "00:00:00" | |||
} | |||
err = models.UpdateJob(job) | |||
if err != nil { | |||
log.Error("UpdateJob failed:", err) | |||
@@ -110,23 +121,35 @@ func GetModelArtsTrainJobVersion(ctx *context.APIContext) { | |||
ctx.JSON(http.StatusOK, map[string]interface{}{ | |||
"JobID": jobID, | |||
"JobStatus": job.Status, | |||
"JobDuration": job.Duration, | |||
"JobDuration": job.TrainJobDuration, | |||
}) | |||
} | |||
func addZero(t int64) (m string) { | |||
if t < 10 { | |||
m = "0" + strconv.FormatInt(t, 10) | |||
return m | |||
} else { | |||
return strconv.FormatInt(t, 10) | |||
} | |||
} | |||
func TrainJobGetLog(ctx *context.APIContext) { | |||
var ( | |||
err error | |||
) | |||
log.Info("test") | |||
var jobID = ctx.Params(":jobid") | |||
var versionName = ctx.Query("version_name") | |||
var logFileName = ctx.Query("file_name") | |||
// var logFileName = ctx.Query("file_name") | |||
var baseLine = ctx.Query("base_line") | |||
var order = ctx.Query("order") | |||
var lines = ctx.Query("lines") | |||
lines_int, err := strconv.Atoi(lines) | |||
if err != nil { | |||
log.Error("change lines(%d) string to int failed", lines_int) | |||
} | |||
if order != modelarts.OrderDesc && order != modelarts.OrderAsc { | |||
log.Error("order(%s) check failed", order) | |||
@@ -136,29 +159,202 @@ func TrainJobGetLog(ctx *context.APIContext) { | |||
return | |||
} | |||
task, err := models.GetCloudbrainByJobIDAndVersionName(jobID, versionName) | |||
resultLogFile, result, err := trainJobGetLogContent(jobID, versionName, baseLine, order, lines_int) | |||
if err != nil { | |||
log.Error("GetCloudbrainByJobIDAndVersionName(%s) failed:%v", jobID, err.Error()) | |||
ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ | |||
"err_msg": "GetCloudbrainByJobIDAndVersionName failed", | |||
}) | |||
log.Error("trainJobGetLog(%s) failed:%v", jobID, err.Error()) | |||
// ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobShow, nil) | |||
return | |||
} | |||
result, err := modelarts.GetTrainJobLog(jobID, strconv.FormatInt(task.VersionID, 10), baseLine, logFileName, order, modelarts.Lines) | |||
ctx.Data["log_file_name"] = resultLogFile.LogFileList[0] | |||
ctx.JSON(http.StatusOK, map[string]interface{}{ | |||
"JobID": jobID, | |||
"LogFileName": resultLogFile.LogFileList[0], | |||
"StartLine": result.StartLine, | |||
"EndLine": result.EndLine, | |||
"Content": result.Content, | |||
"Lines": result.Lines, | |||
}) | |||
} | |||
func trainJobGetLogContent(jobID string, versionName string, baseLine string, order string, lines int) (*models.GetTrainJobLogFileNamesResult, *models.GetTrainJobLogResult, error) { | |||
task, err := models.GetCloudbrainByJobIDAndVersionName(jobID, versionName) | |||
if err != nil { | |||
log.Error("GetCloudbrainByJobID(%s) failed:%v", jobID, err.Error()) | |||
return nil, nil, err | |||
} | |||
resultLogFile, err := modelarts.GetTrainJobLogFileNames(jobID, strconv.FormatInt(task.VersionID, 10)) | |||
if err != nil { | |||
log.Error("GetTrainJobLogFileNames(%s) failed:%v", jobID, err.Error()) | |||
return nil, nil, err | |||
} | |||
result, err := modelarts.GetTrainJobLog(jobID, strconv.FormatInt(task.VersionID, 10), baseLine, resultLogFile.LogFileList[0], order, lines) | |||
if err != nil { | |||
log.Error("GetTrainJobLog(%s) failed:%v", jobID, err.Error()) | |||
ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ | |||
"err_msg": "GetTrainJobLog failed", | |||
}) | |||
return nil, nil, err | |||
} | |||
return resultLogFile, result, err | |||
} | |||
func DelTrainJobVersion(ctx *context.APIContext) { | |||
var ( | |||
err error | |||
) | |||
var jobID = ctx.Params(":jobid") | |||
var versionName = ctx.Query("version_name") | |||
task, err := models.GetCloudbrainByJobIDAndVersionName(jobID, versionName) | |||
if err != nil { | |||
log.Error("GetCloudbrainByJobID(%s) failed:%v", task.JobName, err.Error()) | |||
ctx.NotFound(err) | |||
return | |||
} | |||
_, err = modelarts.DelTrainJobVersion(jobID, strconv.FormatInt(task.VersionID, 10)) | |||
if err != nil { | |||
log.Error("DelTrainJobVersion(%s) failed:%v", task.JobName, err.Error()) | |||
ctx.NotFound(err) | |||
return | |||
} | |||
err = models.DeleteJobVersion(task) | |||
if err != nil { | |||
ctx.ServerError("DeleteJobVersion failed", err) | |||
ctx.NotFound(err) | |||
return | |||
} | |||
//获取删除后的版本数量 | |||
repo := ctx.Repo.Repository | |||
page := ctx.QueryInt("page") | |||
if page <= 0 { | |||
page = 1 | |||
} | |||
VersionListTasks, VersionListCount, err := models.CloudbrainsVersionList(&models.CloudbrainsOptions{ | |||
ListOptions: models.ListOptions{ | |||
Page: page, | |||
PageSize: setting.UI.IssuePagingNum, | |||
}, | |||
RepoID: repo.ID, | |||
Type: models.TypeCloudBrainTwo, | |||
JobType: string(models.JobTypeTrain), | |||
JobID: jobID, | |||
}) | |||
if err != nil { | |||
ctx.ServerError("get VersionListCount faild", err) | |||
return | |||
} | |||
//判断当前的任务是否是最新版本,若是,将排序后的第一个版本设置为最新版本,若不是,最新版本不变,更改最新版本的版本数。 | |||
if task.IsLatestVersion == modelarts.IsLatestVersion { | |||
err = models.SetVersionCountAndLatestVersionByJobIDAndVersionName(jobID, VersionListTasks[0].Cloudbrain.VersionName, VersionListCount, modelarts.IsLatestVersion, VersionListTasks[0].Cloudbrain.TotalVersionCount) | |||
if err != nil { | |||
ctx.ServerError("UpdateJobVersionCount failed", err) | |||
return | |||
} | |||
} else { | |||
latestTask, err := models.GetCloudbrainByJobIDAndIsLatestVersion(jobID, modelarts.IsLatestVersion) | |||
if err != nil { | |||
ctx.ServerError("GetCloudbrainByJobIDAndIsLatestVersion faild:", err) | |||
return | |||
} | |||
err = models.SetVersionCountAndLatestVersionByJobIDAndVersionName(jobID, latestTask.VersionName, VersionListCount, modelarts.IsLatestVersion, VersionListTasks[0].Cloudbrain.TotalVersionCount) | |||
if err != nil { | |||
ctx.ServerError("UpdateJobVersionCount failed", err) | |||
return | |||
} | |||
} | |||
ctx.JSON(http.StatusOK, map[string]interface{}{ | |||
"JobID": jobID, | |||
"StartLine": result.StartLine, | |||
"EndLine": result.EndLine, | |||
"Content": result.Content, | |||
"Lines": result.Lines, | |||
"JobID": jobID, | |||
"VersionName": versionName, | |||
"StatusOK": 0, | |||
}) | |||
} | |||
func StopTrainJobVersion(ctx *context.APIContext) { | |||
var ( | |||
err error | |||
) | |||
var jobID = ctx.Params(":jobid") | |||
var versionName = ctx.Query("version_name") | |||
task, err := models.GetCloudbrainByJobIDAndVersionName(jobID, versionName) | |||
if err != nil { | |||
log.Error("GetCloudbrainByJobID(%s) failed:%v", task.JobName, err.Error()) | |||
return | |||
} | |||
_, err = modelarts.StopTrainJob(jobID, strconv.FormatInt(task.VersionID, 10)) | |||
if err != nil { | |||
log.Error("StopTrainJob(%s) failed:%v", task.JobName, err.Error()) | |||
return | |||
} | |||
ctx.JSON(http.StatusOK, map[string]interface{}{ | |||
"JobID": jobID, | |||
"VersionName": versionName, | |||
"StatusOK": 0, | |||
}) | |||
} | |||
func ModelList(ctx *context.APIContext) { | |||
var ( | |||
err error | |||
) | |||
var jobID = ctx.Params(":jobid") | |||
var versionName = ctx.Query("version_name") | |||
parentDir := ctx.Query("parentDir") | |||
dirArray := strings.Split(parentDir, "/") | |||
task, err := models.GetCloudbrainByJobIDAndVersionName(jobID, versionName) | |||
if err != nil { | |||
log.Error("GetCloudbrainByJobID(%s) failed:%v", task.JobName, err.Error()) | |||
return | |||
} | |||
VersionOutputPath := "V" + strconv.Itoa(task.TotalVersionCount) | |||
models, err := storage.GetObsListObjectVersion(task.JobName, parentDir, VersionOutputPath) | |||
if err != nil { | |||
log.Info("get TrainJobListModel failed:", err) | |||
ctx.ServerError("GetObsListObject:", err) | |||
return | |||
} | |||
ctx.JSON(http.StatusOK, map[string]interface{}{ | |||
"JobID": jobID, | |||
"VersionName": versionName, | |||
"StatusOK": 0, | |||
"Path": dirArray, | |||
"Dirs": models, | |||
"task": task, | |||
"PageIsCloudBrain": true, | |||
}) | |||
} | |||
func ModelDownload(ctx *context.APIContext) { | |||
var ( | |||
err error | |||
) | |||
var jobID = ctx.Params(":jobid") | |||
versionName := ctx.Query("version_name") | |||
parentDir := ctx.Query("parent_dir") | |||
fileName := ctx.Query("file_name") | |||
task, err := models.GetCloudbrainByJobIDAndVersionName(jobID, versionName) | |||
if err != nil { | |||
log.Error("GetCloudbrainByJobID(%s) failed:%v", task.JobName, err.Error()) | |||
return | |||
} | |||
VersionOutputPath := "V" + strconv.Itoa(task.TotalVersionCount) | |||
url, err := storage.GetObsCreateVersionSignedUrl(task.JobName, parentDir, fileName, VersionOutputPath) | |||
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) | |||
} |
@@ -288,6 +288,17 @@ func TrainJobIndex(ctx *context.Context) { | |||
return | |||
} | |||
// for i, task := range tasks { | |||
// result, err := modelarts.GetTrainJob(task.JobID, strconv.FormatInt(task.VersionID, 10)) | |||
// if err != nil { | |||
// log.Error("GetJob(%s) failed:%v", task.JobID, err.Error()) | |||
// return | |||
// } | |||
// // tasks[i].Status = modelarts.TransTrainJobStatus(result.Status) | |||
// tasks[i].Status = result.Status | |||
// tasks[i].Duration = result.Duration | |||
// } | |||
pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, 5) | |||
pager.SetDefaultParams(ctx) | |||
ctx.Data["Page"] = pager | |||
@@ -463,7 +474,7 @@ func trainJobNewVersionDataPrepare(ctx *context.Context) error { | |||
ctx.Data["dataset_name"] = task.DatasetName | |||
ctx.Data["work_server_number"] = task.WorkServerNumber | |||
ctx.Data["flavor_name"] = task.FlavorName | |||
ctx.Data["engine_name"] = task.FlavorName | |||
ctx.Data["engine_name"] = task.EngineName | |||
ctx.Data["uuid"] = task.Uuid | |||
ctx.Data["flavor_code"] = task.FlavorCode | |||
ctx.Data["engine_id"] = task.EngineID | |||
@@ -480,6 +491,7 @@ func trainJobNewVersionDataPrepare(ctx *context.Context) error { | |||
func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) { | |||
ctx.Data["PageIsTrainJob"] = true | |||
VersionOutputPath := "V" + strconv.Itoa(modelarts.TotalVersionCount) | |||
jobName := form.JobName | |||
uuid := form.Attachment | |||
description := form.Description | |||
@@ -493,8 +505,8 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||
repo := ctx.Repo.Repository | |||
codeLocalPath := setting.JobPath + jobName + modelarts.CodePath | |||
codeObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.CodePath | |||
outputObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.OutputPath | |||
logObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.LogPath | |||
outputObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.OutputPath + VersionOutputPath + "/" | |||
logObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.LogPath + VersionOutputPath + "/" | |||
dataPath := "/" + setting.Bucket + "/" + setting.BasePath + path.Join(uuid[0:1], uuid[1:2]) + "/" + uuid + uuid + "/" | |||
branch_name := form.BranchName | |||
isLatestVersion := modelarts.IsLatestVersion | |||
@@ -543,14 +555,15 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||
} | |||
//todo: upload code (send to file_server todo this work?) | |||
if err := obsMkdir(setting.CodePathPrefix + jobName + modelarts.OutputPath); err != nil { | |||
if err := obsMkdir(setting.CodePathPrefix + jobName + modelarts.OutputPath + VersionOutputPath + "/"); err != nil { | |||
// if err := obsMkdir(setting.CodePathPrefix + jobName + modelarts.OutputPath); err != nil { | |||
log.Error("Failed to obsMkdir_output: %s (%v)", repo.FullName(), err) | |||
trainJobNewDataPrepare(ctx) | |||
ctx.RenderWithErr("Failed to obsMkdir_output", tplModelArtsTrainJobNew, &form) | |||
return | |||
} | |||
if err := obsMkdir(setting.CodePathPrefix + jobName + modelarts.LogPath); err != nil { | |||
if err := obsMkdir(setting.CodePathPrefix + jobName + modelarts.LogPath + VersionOutputPath + "/"); err != nil { | |||
log.Error("Failed to obsMkdir_log: %s (%v)", repo.FullName(), err) | |||
trainJobNewDataPrepare(ctx) | |||
ctx.RenderWithErr("Failed to obsMkdir_log", tplModelArtsTrainJobNew, &form) | |||
@@ -629,28 +642,29 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||
} | |||
req := &modelarts.GenerateTrainJobReq{ | |||
JobName: jobName, | |||
DataUrl: dataPath, | |||
Description: description, | |||
CodeObsPath: codeObsPath, | |||
BootFileUrl: codeObsPath + bootFile, | |||
BootFile: bootFile, | |||
TrainUrl: outputObsPath, | |||
FlavorCode: flavorCode, | |||
WorkServerNumber: workServerNumber, | |||
EngineID: int64(engineID), | |||
LogUrl: logObsPath, | |||
PoolID: poolID, | |||
Uuid: uuid, | |||
Parameters: parameters.Parameter, | |||
CommitID: commitID, | |||
IsLatestVersion: isLatestVersion, | |||
BranchName: branch_name, | |||
Params: form.Params, | |||
FatherVersionName: modelarts.InitFatherVersionName, | |||
JobName: jobName, | |||
DataUrl: dataPath, | |||
Description: description, | |||
CodeObsPath: codeObsPath, | |||
BootFileUrl: codeObsPath + bootFile, | |||
BootFile: bootFile, | |||
TrainUrl: outputObsPath, | |||
FlavorCode: flavorCode, | |||
WorkServerNumber: workServerNumber, | |||
EngineID: int64(engineID), | |||
LogUrl: logObsPath, | |||
PoolID: poolID, | |||
Uuid: uuid, | |||
Parameters: parameters.Parameter, | |||
CommitID: commitID, | |||
IsLatestVersion: isLatestVersion, | |||
BranchName: branch_name, | |||
Params: form.Params, | |||
// FatherVersionName: InitVersionName, | |||
FlavorName: FlavorName, | |||
EngineName: EngineName, | |||
VersionCount: VersionCount, | |||
TotalVersionCount: modelarts.TotalVersionCount, | |||
} | |||
err = modelarts.GenerateTrainJob(ctx, req) | |||
@@ -665,42 +679,20 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||
ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobNew, &form) | |||
return | |||
} | |||
// // 保存openi创建训练任务界面的参数 | |||
// err = models.CreateTrainjobConfigDetail(&models.TrainjobConfigDetail{ | |||
// JobName: req.JobName, | |||
// JobID: strconv.FormatInt(jobResult.JobID, 10), | |||
// VersionName: jobResult.VersionName, | |||
// ResourcePools: form.PoolID, | |||
// EngineVersions: form.EngineID, | |||
// FlavorInfos: form.Flavor, | |||
// TrainUrl: outputObsPath, | |||
// BootFile: form.BootFile, | |||
// Uuid: form.Attachment, | |||
// DatasetName: attach.Name, | |||
// Params: form.Params, | |||
// BranchName: branch_name, | |||
// }) | |||
// if err != nil { | |||
// log.Error("CreateTrainjobConfigDetail failed:%v", err.Error()) | |||
// trainJobNewVersionDataPrepare(ctx) | |||
// ctx.Data["bootFile"] = form.BootFile | |||
// ctx.Data["uuid"] = form.Attachment | |||
// ctx.Data["datasetName"] = attach.Name | |||
// ctx.Data["params"] = form.Params | |||
// ctx.Data["branch_name"] = branch_name | |||
// ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobVersionNew, &form) | |||
// return | |||
// } | |||
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/train-job") | |||
} | |||
func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) { | |||
ctx.Data["PageIsTrainJob"] = true | |||
var jobID = ctx.Params(":jobid") | |||
// var versionName = ctx.Params(":version-name") | |||
var versionName = ctx.Query("version_name") | |||
latestTask, err := models.GetCloudbrainByJobIDAndIsLatestVersion(jobID, modelarts.IsLatestVersion) | |||
if err != nil { | |||
ctx.ServerError("GetCloudbrainByJobIDAndIsLatestVersion faild:", err) | |||
return | |||
} | |||
VersionOutputPath := "V" + strconv.Itoa(latestTask.TotalVersionCount+1) | |||
jobName := form.JobName | |||
uuid := form.Attachment | |||
@@ -715,11 +707,11 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ | |||
repo := ctx.Repo.Repository | |||
codeLocalPath := setting.JobPath + jobName + modelarts.CodePath | |||
codeObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.CodePath | |||
outputObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.OutputPath | |||
logObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.LogPath | |||
outputObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.OutputPath + VersionOutputPath + "/" | |||
logObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.LogPath + VersionOutputPath + "/" | |||
dataPath := "/" + setting.Bucket + "/" + setting.BasePath + path.Join(uuid[0:1], uuid[1:2]) + "/" + uuid + uuid + "/" | |||
branch_name := form.BranchName | |||
fatherVersionName := versionName | |||
fatherVersionName := form.VersionName | |||
FlavorName := form.FlavorName | |||
EngineName := form.EngineName | |||
@@ -762,14 +754,14 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ | |||
} | |||
//todo: upload code (send to file_server todo this work?) | |||
if err := obsMkdir(setting.CodePathPrefix + jobName + modelarts.OutputPath); err != nil { | |||
if err := obsMkdir(setting.CodePathPrefix + jobName + modelarts.OutputPath + VersionOutputPath + "/"); err != nil { | |||
log.Error("Failed to obsMkdir_output: %s (%v)", repo.FullName(), err) | |||
trainJobNewVersionDataPrepare(ctx) | |||
ctx.RenderWithErr("Failed to obsMkdir_output", tplModelArtsTrainJobVersionNew, &form) | |||
return | |||
} | |||
if err := obsMkdir(setting.CodePathPrefix + jobName + modelarts.LogPath); err != nil { | |||
if err := obsMkdir(setting.CodePathPrefix + jobName + modelarts.LogPath + VersionOutputPath + "/"); err != nil { | |||
log.Error("Failed to obsMkdir_log: %s (%v)", repo.FullName(), err) | |||
trainJobNewVersionDataPrepare(ctx) | |||
ctx.RenderWithErr("Failed to obsMkdir_log", tplModelArtsTrainJobVersionNew, &form) | |||
@@ -860,27 +852,30 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ | |||
return | |||
} | |||
req := &modelarts.GenerateTrainJobVersionReq{ | |||
JobName: task.JobName, | |||
DataUrl: dataPath, | |||
Description: description, | |||
CodeObsPath: codeObsPath, | |||
BootFileUrl: codeObsPath + bootFile, | |||
BootFile: bootFile, | |||
TrainUrl: outputObsPath, | |||
FlavorCode: flavorCode, | |||
WorkServerNumber: workServerNumber, | |||
EngineID: int64(engineID), | |||
LogUrl: logObsPath, | |||
PoolID: poolID, | |||
Uuid: uuid, | |||
Params: form.Params, | |||
PreVersionId: task.VersionID, | |||
CommitID: commitID, | |||
BranchName: branch_name, | |||
FlavorName: FlavorName, | |||
EngineName: EngineName, | |||
JobName: task.JobName, | |||
DataUrl: dataPath, | |||
Description: description, | |||
CodeObsPath: codeObsPath, | |||
BootFileUrl: codeObsPath + bootFile, | |||
BootFile: bootFile, | |||
TrainUrl: outputObsPath, | |||
FlavorCode: flavorCode, | |||
WorkServerNumber: workServerNumber, | |||
EngineID: int64(engineID), | |||
LogUrl: logObsPath, | |||
PoolID: poolID, | |||
Uuid: uuid, | |||
Params: form.Params, | |||
Parameters: parameters.Parameter, | |||
PreVersionId: task.VersionID, | |||
CommitID: commitID, | |||
BranchName: branch_name, | |||
FlavorName: FlavorName, | |||
EngineName: EngineName, | |||
FatherVersionName: fatherVersionName, | |||
TotalVersionCount: latestTask.TotalVersionCount + 1, | |||
} | |||
err = modelarts.GenerateTrainJobVersion(ctx, req, jobID, fatherVersionName) | |||
err = modelarts.GenerateTrainJobVersion(ctx, req, jobID) | |||
if err != nil { | |||
log.Error("GenerateTrainJob failed:%v", err.Error()) | |||
trainJobNewVersionDataPrepare(ctx) | |||
@@ -891,36 +886,8 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ | |||
ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobVersionNew, &form) | |||
return | |||
} | |||
// 保存openi创建训练任务界面的参数 | |||
// err = models.CreateTrainjobConfigDetail(&models.TrainjobConfigDetail{ | |||
// JobName: req.JobName, | |||
// JobID: strconv.FormatInt(jobResult.JobID, 10), | |||
// VersionName: jobResult.VersionName, | |||
// ResourcePools: form.PoolID, | |||
// EngineVersions: form.EngineID, | |||
// FlavorInfos: form.Flavor, | |||
// TrainUrl: outputObsPath, | |||
// BootFile: form.BootFile, | |||
// Uuid: form.Attachment, | |||
// DatasetName: attach.Name, | |||
// Params: form.Params, | |||
// BranchName: branch_name, | |||
// }) | |||
// if err != nil { | |||
// log.Error("CreateTrainjobConfigDetail failed:%v", err.Error()) | |||
// trainJobNewVersionDataPrepare(ctx) | |||
// ctx.Data["bootFile"] = form.BootFile | |||
// ctx.Data["uuid"] = form.Attachment | |||
// ctx.Data["datasetName"] = attach.Name | |||
// ctx.Data["params"] = form.Params | |||
// ctx.Data["branch_name"] = branch_name | |||
// ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobVersionNew, &form) | |||
// return | |||
// } | |||
// ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/train-job") | |||
ctx.HTML(http.StatusOK, tplModelArtsTrainJobShow) | |||
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/train-job") | |||
// ctx.HTML(http.StatusOK, tplModelArtsTrainJobShow) | |||
} | |||
// readDir reads the directory named by dirname and returns | |||
@@ -1014,11 +981,6 @@ func TrainJobShow(ctx *context.Context) { | |||
ctx.Data["PageIsCloudBrain"] = true | |||
var jobID = ctx.Params(":jobid") | |||
task, err := models.GetCloudbrainByJobID(jobID) | |||
if err != nil { | |||
ctx.ServerError("GetCloudbrainByJobID faild", err) | |||
return | |||
} | |||
repo := ctx.Repo.Repository | |||
page := ctx.QueryInt("page") | |||
@@ -1035,74 +997,48 @@ func TrainJobShow(ctx *context.Context) { | |||
JobType: string(models.JobTypeTrain), | |||
JobID: jobID, | |||
}) | |||
if err != nil { | |||
ctx.ServerError("Cloudbrain", err) | |||
return | |||
} | |||
if err != nil { | |||
log.Error("GetCloudbrainByJobID(%s) failed:%v", jobID, err.Error()) | |||
log.Error("GetVersionListTasks(%s) failed:%v", jobID, err.Error()) | |||
ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobShow, nil) | |||
return | |||
} | |||
//将运行参数转化为epoch_size = 3, device_target = Ascend的格式 | |||
for i, _ := range VersionListTasks { | |||
// attach, err := models.GetAttachmentByUUID(task.Uuid) | |||
// if err != nil { | |||
// log.Error("GetAttachmentByUUID(%s) failed:%v", jobID, err.Error()) | |||
// ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobShow, nil) | |||
// return | |||
// } | |||
var parameters models.Parameters | |||
result, err := modelarts.GetTrainJob(jobID, strconv.FormatInt(task.VersionID, 10)) | |||
if err != nil { | |||
log.Error("GetJob(%s) failed:%v", jobID, err.Error()) | |||
ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobShow, nil) | |||
return | |||
} | |||
if result != nil { | |||
result.CreateTime = time.Unix(int64(result.LongCreateTime/1000), 0).Format("2006-01-02 15:04:05") | |||
if result.Duration != 0 { | |||
result.TrainJobDuration = addZero(result.Duration/3600000) + ":" + addZero(result.Duration%3600000/60000) + ":" + addZero(result.Duration%60000/1000) | |||
} else { | |||
result.TrainJobDuration = "00:00:00" | |||
} | |||
result.Status = modelarts.TransTrainJobStatus(result.IntStatus) | |||
err = models.SetTrainJobStatusByJobID(jobID, result.Status, result.Duration, string(result.TrainJobDuration)) | |||
err := json.Unmarshal([]byte(VersionListTasks[i].Parameters), ¶meters) | |||
if err != nil { | |||
ctx.ServerError("UpdateJob failed", err) | |||
log.Error("Failed to Unmarshal Parameters: %s (%v)", VersionListTasks[i].Parameters, err) | |||
trainJobNewDataPrepare(ctx) | |||
return | |||
} | |||
result.DatasetName = task.DatasetName | |||
} | |||
resultLogFile, resultLog, err := trainJobGetLog(jobID) | |||
if err != nil { | |||
log.Error("trainJobGetLog(%s) failed:%v", jobID, err.Error()) | |||
ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobShow, nil) | |||
return | |||
if len(parameters.Parameter) > 0 { | |||
paramTemp := "" | |||
for _, Parameter := range parameters.Parameter { | |||
param := Parameter.Label + " = " + Parameter.Value + ", " | |||
paramTemp = paramTemp + param | |||
} | |||
VersionListTasks[i].Parameters = paramTemp[:len(paramTemp)-2] | |||
} | |||
} | |||
ctx.Data["log_file_name"] = resultLogFile.LogFileList[0] | |||
ctx.Data["log"] = resultLog | |||
ctx.Data["task"] = task | |||
ctx.Data["jobID"] = jobID | |||
ctx.Data["result"] = result | |||
ctx.Data["version_list_task"] = VersionListTasks | |||
ctx.Data["version_list_count"] = VersionListCount | |||
ctx.HTML(http.StatusOK, tplModelArtsTrainJobShow) | |||
} | |||
func addZero(t int64) (m string) { | |||
if t < 10 { | |||
m = "0" + strconv.FormatInt(t, 10) | |||
return m | |||
} else { | |||
return strconv.FormatInt(t, 10) | |||
} | |||
} | |||
// func addZero(t int64) (m string) { | |||
// if t < 10 { | |||
// m = "0" + strconv.FormatInt(t, 10) | |||
// return m | |||
// } else { | |||
// return strconv.FormatInt(t, 10) | |||
// } | |||
// } | |||
func TrainJobGetLog(ctx *context.Context) { | |||
ctx.Data["PageIsTrainJob"] = true | |||
@@ -1160,26 +1096,40 @@ func trainJobGetLog(jobID string) (*models.GetTrainJobLogFileNamesResult, *model | |||
func TrainJobDel(ctx *context.Context) { | |||
var jobID = ctx.Params(":jobid") | |||
task, err := models.GetCloudbrainByJobID(jobID) | |||
repo := ctx.Repo.Repository | |||
page := ctx.QueryInt("page") | |||
if page <= 0 { | |||
page = 1 | |||
} | |||
VersionListTasks, _, err := models.CloudbrainsVersionList(&models.CloudbrainsOptions{ | |||
ListOptions: models.ListOptions{ | |||
Page: page, | |||
PageSize: setting.UI.IssuePagingNum, | |||
}, | |||
RepoID: repo.ID, | |||
Type: models.TypeCloudBrainTwo, | |||
JobType: string(models.JobTypeTrain), | |||
JobID: jobID, | |||
}) | |||
if err != nil { | |||
log.Error("GetCloudbrainByJobID(%s) failed:%v", task.JobName, err.Error()) | |||
ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobIndex, nil) | |||
ctx.ServerError("get VersionListTasks failed", err) | |||
return | |||
} | |||
for _, task := range VersionListTasks { | |||
err = models.DeleteJobVersion(&task.Cloudbrain) | |||
if err != nil { | |||
ctx.ServerError("DeleteJobVersion failed", err) | |||
return | |||
} | |||
} | |||
_, err = modelarts.DelTrainJob(jobID) | |||
if err != nil { | |||
log.Error("DelTrainJob(%s) failed:%v", task.JobName, err.Error()) | |||
log.Error("DelTrainJob(%s) failed:%v", jobID, err.Error()) | |||
ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobIndex, nil) | |||
return | |||
} | |||
err = models.DeleteJob(task) | |||
if err != nil { | |||
ctx.ServerError("DeleteJob failed", err) | |||
return | |||
} | |||
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/train-job") | |||
} | |||
@@ -1202,54 +1152,6 @@ func TrainJobStop(ctx *context.Context) { | |||
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/train-job") | |||
} | |||
func TrainJobVersionDel(ctx *context.Context) { | |||
var jobID = ctx.Params(":jobid") | |||
var versionName = ctx.Query(":versionName") | |||
task, err := models.GetCloudbrainByJobIDAndVersionName(jobID, versionName) | |||
if err != nil { | |||
log.Error("GetCloudbrainByJobID(%s) failed:%v", task.JobName, err.Error()) | |||
ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobShow, nil) | |||
return | |||
} | |||
_, err = modelarts.DelTrainJob(jobID) | |||
if err != nil { | |||
log.Error("DelTrainJob(%s) failed:%v", task.JobName, err.Error()) | |||
ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobShow, nil) | |||
return | |||
} | |||
err = models.DeleteJob(task) | |||
if err != nil { | |||
ctx.ServerError("DeleteJob failed", err) | |||
return | |||
} | |||
// ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/train-job") | |||
ctx.HTML(http.StatusOK, tplModelArtsTrainJobShow) | |||
} | |||
func TrainJobVersionStop(ctx *context.Context) { | |||
var jobID = ctx.Params(":jobid") | |||
var versionName = ctx.Query(":versionName") | |||
task, err := models.GetCloudbrainByJobIDAndVersionName(jobID, versionName) | |||
if err != nil { | |||
log.Error("GetCloudbrainByJobID(%s) failed:%v", task.JobName, err.Error()) | |||
ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobIndex, nil) | |||
return | |||
} | |||
_, err = modelarts.StopTrainJob(jobID, strconv.FormatInt(task.VersionID, 10)) | |||
if err != nil { | |||
log.Error("StopTrainJob(%s) failed:%v", task.JobName, err.Error()) | |||
ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobIndex, nil) | |||
return | |||
} | |||
// ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/train-job") | |||
ctx.HTML(http.StatusOK, tplModelArtsTrainJobShow) | |||
} | |||
func canUserCreateTrainJob(uid int64) (bool, error) { | |||
org, err := models.GetOrgByName(setting.AllowedOrg) | |||
if err != nil { | |||
@@ -1350,15 +1252,17 @@ func TrainJobVersionShowModels(ctx *context.Context) { | |||
jobID := ctx.Params(":jobid") | |||
parentDir := ctx.Query("parentDir") | |||
versionName := ctx.Query("version_name") | |||
dirArray := strings.Split(parentDir, "/") | |||
// dirArray := strings.Split(parentDir, "/") | |||
task, err := models.GetCloudbrainByJobIDAndVersionName(jobID, versionName) | |||
if err != nil { | |||
log.Error("no such job!", ctx.Data["msgID"]) | |||
ctx.ServerError("no such job:", err) | |||
return | |||
} | |||
parentDir = versionName | |||
models, err := storage.GetVersionObsListObject(task.JobName, parentDir) | |||
// parentDir = versionName | |||
VersionOutputPath := "V" + strconv.Itoa(task.TotalVersionCount) | |||
dirArray := strings.Split(VersionOutputPath, "/") | |||
models, err := storage.GetObsListObjectVersion(task.JobName, parentDir, VersionOutputPath) | |||
if err != nil { | |||
log.Info("get TrainJobListModel failed:", err) | |||
ctx.ServerError("GetVersionObsListObject:", err) | |||
@@ -1366,6 +1270,7 @@ func TrainJobVersionShowModels(ctx *context.Context) { | |||
} | |||
ctx.Data["Path"] = dirArray | |||
// ctx.Data["Path"] = VersionOutputPath | |||
ctx.Data["Dirs"] = models | |||
ctx.Data["task"] = task | |||
ctx.Data["JobID"] = jobID | |||
@@ -1384,3 +1289,26 @@ func TrainJobDownloadModel(ctx *context.Context) { | |||
} | |||
http.Redirect(ctx.Resp, ctx.Req.Request, url, http.StatusMovedPermanently) | |||
} | |||
func TrainJobVersionDownloadModel(ctx *context.Context) { | |||
var jobID = ctx.Params(":jobid") | |||
parentDir := ctx.Query("parentDir") | |||
fileName := ctx.Query("fileName") | |||
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 | |||
} | |||
VersionOutputPath := "V" + strconv.Itoa(task.TotalVersionCount) | |||
url, err := storage.GetObsCreateVersionSignedUrl(task.JobName, parentDir, fileName, VersionOutputPath) | |||
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) | |||
} |
@@ -997,23 +997,14 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
m.Get("", reqRepoCloudBrainReader, repo.TrainJobShow) | |||
m.Post("/stop", reqRepoCloudBrainWriter, repo.TrainJobStop) | |||
m.Post("/del", reqRepoCloudBrainWriter, repo.TrainJobDel) | |||
m.Get("/log", reqRepoCloudBrainReader, repo.TrainJobGetLog) | |||
m.Get("/models", reqRepoCloudBrainReader, repo.TrainJobShowModels) | |||
m.Get("/download_model", reqRepoCloudBrainReader, repo.TrainJobDownloadModel) | |||
m.Get("/version_models", reqRepoCloudBrainReader, repo.TrainJobVersionShowModels) | |||
// m.Group("/:version-name", func() { | |||
m.Get("/models", reqRepoCloudBrainReader, repo.TrainJobVersionShowModels) | |||
m.Get("/download_model", reqRepoCloudBrainReader, repo.TrainJobVersionDownloadModel) | |||
m.Get("/create_version", reqRepoCloudBrainReader, repo.TrainJobNewVersion) | |||
m.Post("/create_version", reqRepoCloudBrainWriter, bindIgnErr(auth.CreateModelArtsTrainJobForm{}), repo.TrainJobCreateVersion) | |||
// }) | |||
m.Post("/stop_version", reqRepoCloudBrainWriter, repo.TrainJobVersionStop) | |||
m.Post("/del_version", reqRepoCloudBrainWriter, repo.TrainJobVersionDel) | |||
}) | |||
m.Get("/create", reqRepoCloudBrainReader, repo.TrainJobNew) | |||
m.Post("/create", reqRepoCloudBrainWriter, bindIgnErr(auth.CreateModelArtsTrainJobForm{}), repo.TrainJobCreate) | |||
// m.Get("/create", reqRepoCloudBrainReader, repo.TrainJobNewVersion) | |||
// m.Post("/create", reqRepoCloudBrainWriter, bindIgnErr(auth.CreateModelArtsTrainJobForm{}), repo.TrainJobCreateVersion) | |||
m.Get("/para-config-list", reqRepoCloudBrainReader, repo.TrainJobGetConfigList) | |||
}) | |||
}, context.RepoRef()) | |||
@@ -6,7 +6,19 @@ | |||
{{template "base/alert" .}} | |||
<h4 class="ui header" id="vertical-segment"> | |||
<a href="javascript:window.history.back();"><i class="arrow left icon"></i>返回</a> | |||
<div class="ui breadcrumb"> | |||
<a class="section" href="{{.RepoLink}}/cloudbrain"> | |||
{{.i18n.Tr "repo.cloudbrain"}} | |||
</a> | |||
<div class="divider"> / </div> | |||
<a class="section" href="{{.RepoLink}}/modelarts/notebook"> | |||
{{$.i18n.Tr "repo.modelarts.notebook"}} | |||
</a> | |||
<div class="divider"> / </div> | |||
{{with .task}} | |||
<div class="active section">{{.JobName}}</div> | |||
{{end}} | |||
</div> | |||
</h4> | |||
<div> | |||
<div class="ui yellow segment"> | |||
@@ -6,7 +6,19 @@ | |||
{{template "base/alert" .}} | |||
<h4 class="ui header" id="vertical-segment"> | |||
<a href="javascript:window.history.back();"><i class="arrow left icon"></i>返回</a> | |||
<div class="ui breadcrumb"> | |||
<a class="section" href="{{.RepoLink}}/cloudbrain"> | |||
{{.i18n.Tr "repo.cloudbrain"}} | |||
</a> | |||
<div class="divider"> / </div> | |||
<a class="section" href="{{.RepoLink}}/cloudbrain"> | |||
{{$.i18n.Tr "repo.modelarts.notebook"}} | |||
</a> | |||
<div class="divider"> / </div> | |||
{{with .task}} | |||
<div class="active section">{{.JobName}}</div> | |||
{{end}} | |||
</div> | |||
</h4> | |||
<div> | |||
<div class="ui yellow segment"> | |||
@@ -333,7 +333,7 @@ | |||
</div> | |||
<!-- 任务状态 --> | |||
<div class="two wide column padding0" style="padding-left: 2.2rem !important;"> | |||
<span class="job-status" id="{{.JobID}}" data-repopath="{{$.RepoRelPath}}" data-jobid="{{.JobID}}"> | |||
<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> | |||
@@ -381,12 +381,12 @@ | |||
{{end}} | |||
</form> | |||
</div> | |||
<div class="ui compact buttons"> | |||
<!-- 模型下载 --> | |||
<!-- 模型下载 --> | |||
<!-- <div class="ui compact buttons"> | |||
<a style="padding: 0.5rem;" class="ui basic blue button" href="{{$.Link}}/{{.JobID}}/models" target="_blank"> | |||
{{$.i18n.Tr "repo.model_download"}} | |||
</a> | |||
</div> | |||
</div> --> | |||
<!-- 删除任务 --> | |||
<form class="ui compact buttons" id="delForm-{{.JobID}}" action="{{$.Link}}/{{.JobID}}/del" method="post"> | |||
{{$.CsrfTokenHtml}} | |||
@@ -442,6 +442,8 @@ | |||
{{template "base/footer" .}} | |||
<script> | |||
console.log({{.Tasks}}) | |||
// 调试和评分新开窗口 | |||
function stop(obj) { | |||
if (obj.style.color != "rgb(204, 204, 204)") { | |||
@@ -491,11 +493,12 @@ | |||
$(".job-status").each((index, job) => { | |||
const jobID = job.dataset.jobid; | |||
const repoPath = job.dataset.repopath; | |||
$.get(`/api/v1/repos/${repoPath}/modelarts/train-job/${jobID}`, (data) => { | |||
const versionname = job.dataset.version | |||
$.get(`/api/v1/repos/${repoPath}/modelarts/train-job/${jobID}?version_name=${versionname}`, (data) => { | |||
console.log(data) | |||
const duration = data.JobDuration | |||
const jobID = data.JobID | |||
let train_duration = runtime(duration) | |||
$('#duration-'+jobID).text(train_duration) | |||
$('#duration-'+jobID).text(duration) | |||
}) | |||
}) | |||
@@ -508,17 +511,18 @@ | |||
$(".job-status").each((index, job) => { | |||
const jobID = job.dataset.jobid; | |||
const repoPath = job.dataset.repopath; | |||
const versionname = job.dataset.version | |||
if (job.textContent.trim() == 'IMAGE_FAILED' || job.textContent.trim() == 'SUBMIT_FAILED' || job.textContent.trim() == 'DELETE_FAILED' | |||
|| job.textContent.trim() == 'KILLED' || job.textContent.trim() == 'COMPLETED' || job.textContent.trim() == 'FAILED' | |||
|| job.textContent.trim() == 'CANCELED' || job.textContent.trim() == 'LOST') { | |||
return | |||
} | |||
$.get(`/api/v1/repos/${repoPath}/modelarts/train-job/${jobID}`, (data) => { | |||
$.get(`/api/v1/repos/${repoPath}/modelarts/train-job/${jobID}?version_name=${versionname}`, (data) => { | |||
const jobID = data.JobID | |||
const 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) | |||
@@ -527,8 +531,7 @@ | |||
if(status==="RUNNING"){ | |||
$('#model-debug-'+jobID).removeClass('disabled') | |||
$('#model-debug-'+jobID).addClass('blue') | |||
let train_duration = runtime(duration) | |||
$('#duration-'+jobID).text(train_duration) | |||
// $('#duration-'+jobID).text(duration) | |||
} | |||
if(status!=="RUNNING"){ | |||
@@ -542,7 +545,7 @@ | |||
$('#model-delete-'+jobID).removeClass('red') | |||
$('#model-delete-'+jobID).addClass('disabled') | |||
} | |||
if(status=="KILLED" || status=="FAILED" || status=="KILLING"){ | |||
if(status=="KILLED" || status=="FAILED" || status=="KILLING" || status=="COMPLETED"){ | |||
$('#stop-model-debug-'+jobID).removeClass('blue') | |||
$('#stop-model-debug-'+jobID).addClass('disabled') | |||
$('#model-delete-'+jobID).removeClass('disabled') | |||
@@ -103,7 +103,9 @@ | |||
-webkit-animation-delay: -0.8s; | |||
animation-delay: -0.8s; | |||
} | |||
.left2{ | |||
margin-left: -2px; | |||
} | |||
@-webkit-keyframes sk-stretchdelay { | |||
0%, | |||
40%, | |||
@@ -172,7 +174,7 @@ | |||
<div class="required unite min_title inline field"> | |||
<label>{{.i18n.Tr "repo.modelarts.code_version"}}</label> | |||
<select class="ui dropdown width80" id="code_version" name="branch_name"> | |||
<select class="ui dropdown width80 left2" id="code_version" name="branch_name"> | |||
{{range $k, $v :=.Branches}} | |||
<option name="branch_name" value="{{$v}}">{{$v}}</option> | |||
{{end}} | |||
@@ -22,6 +22,7 @@ | |||
vertical-align: middle; | |||
display: inline-block; | |||
width: calc(100% - 32px); | |||
cursor: default; | |||
} | |||
.acc-margin-bottom { | |||
margin-bottom: 5px; | |||
@@ -55,7 +56,7 @@ | |||
margin:10px 5px ; | |||
} | |||
.tab_2_content { | |||
min-height: 260px; | |||
min-height: 360px; | |||
margin-left: 10px; | |||
} | |||
.ac-grid { | |||
@@ -83,6 +84,7 @@ | |||
.ti-text-form-label { | |||
padding-bottom: 20px; | |||
padding-right: 20px; | |||
color: #8a8e99; | |||
font-size: 12px; | |||
white-space: nowrap; | |||
@@ -105,38 +107,102 @@ td, th { | |||
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"> | |||
<a href="javascript:window.history.back();"><i class="arrow left icon"></i>返回</a> | |||
<!-- <a href="javascript:window.history.back();"><i class="arrow left icon"></i>返回</a> --> | |||
<div class="ui breadcrumb"> | |||
<a class="section" href="{{.RepoLink}}/cloudbrain"> | |||
{{.i18n.Tr "repo.cloudbrain"}} | |||
</a> | |||
<div class="divider"> / </div> | |||
<a class="section" href="{{$.RepoLink}}/modelarts/train-job"> | |||
{{$.i18n.Tr "repo.modelarts.train_job"}} | |||
</a> | |||
<div class="divider"> / </div> | |||
<div class="active section"></div> | |||
</div> | |||
</h4> | |||
{{range .version_list_task}} | |||
<div class="ui accordion"> | |||
<div class="title padding0"> | |||
{{range $k ,$v := .version_list_task}} | |||
<div class="ui accordion border-according" id="accordion{{.VersionName}}" data-repopath="{{$.RepoRelPath}}" data-jobid="{{.JobID}}" data-version="{{.VersionName}}"> | |||
<div class="{{if eq $k 0}}active{{end}} title padding0"> | |||
<div class="according-panel-heading"> | |||
<div class="accordion-panel-title"> | |||
<i class="dropdown icon"></i> | |||
<span class="accordion-panel-title-content"> | |||
<span> | |||
<div style="float: right;"> | |||
<button>创建模型</button> | |||
<a href="{{$.RepoLink}}/modelarts/train-job/{{.JobID}}/create_version?version_name={{.VersionName}}">修改</a> | |||
<button>停止</button> | |||
<button>删除</button> | |||
<a class="ti-action-menu-item {{if ne .Status "COMPLETED"}}disabled {{end}}">创建模型</a> | |||
<a class="ti-action-menu-item" href="{{$.RepoLink}}/modelarts/train-job/{{.JobID}}/create_version?version_name={{.VersionName}}">修改</a> | |||
<a class="ti-action-menu-item {{if eq .Status "KILLED" "FAILED" "START_FAILED" "KILLING" "COMPLETED"}}disabled {{end}}" id="{{.VersionName}}-stop" onclick="stopVersion({{.VersionName}})">停止</a> | |||
<a class="ti-action-menu-item " href="{{$.Link}}/models?version_name={{.VersionName}}" target="_blank">模型下载</a> | |||
<a class="ti-action-menu-item" onclick="deleteVersion({{.VersionName}})" style="color: #FF4D4F;">删除</a> | |||
</div> | |||
<div class="ac-display-inblock title_text acc-margin-bottom"> | |||
<span class="cti-mgRight-sm">2021/11/08 19:35:19</span> | |||
<span class="cti-mgRight-sm"> 当前版本:{{.VersionName}}</span> | |||
<span class="cti-mgRight-sm"> 父版本:{{.FatherVersionName}}</span> | |||
<span class="cti-mgRight-sm ac-text-normal title_text">状态 | |||
<span><i id="icon" style="vertical-align: middle;" class=""></i><span id="text" style="margin-left: 0.4em;font-size: 12px;">运行成功</span></span> | |||
<span class="cti-mgRight-sm ac-text-normal title_text">状态: | |||
<span id="{{.VersionName}}-status-span"><i id="icon" style="vertical-align: middle;" class="{{.Status}}"></i><span id="text" style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span> | |||
</span> | |||
<span class="ac-text-normal title_text">运行时间:</span> | |||
<span class="cti-mgRight-sm uc-accordionTitle-black">01:09:50</span> | |||
<span data-tooltip="刷新" data-inverted=""><i class="redo icon"></i></span> | |||
<span class="cti-mgRight-sm uc-accordionTitle-black" id="{{.VersionName}}-duration-span">{{.TrainJobDuration}}</span> | |||
<span data-tooltip="刷新" style="cursor: pointer;" data-inverted="" onclick="refreshStatus({{.VersionName}})"><i class="redo icon redo-color"></i></span> | |||
</div> | |||
</span> | |||
@@ -144,14 +210,15 @@ td, th { | |||
</div> | |||
</div> | |||
</div> | |||
<div class="content accordion-border"> | |||
<div class="{{if eq $k 0}}active{{end}} content accordion-border"> | |||
<div class="content-pad"> | |||
<div class="ui pointing secondary menu"> | |||
<a class="active item" data-tab="first">配置信息</a> | |||
<a class="item" data-tab="second">日志文件</a> | |||
<a class="item" data-tab="third">模型下载</a> | |||
<a class="active item" data-tab="first{{$k}}">配置信息</a> | |||
<a class="item" data-tab="second{{$k}}" onclick="loadLog({{.VersionName}})">日志文件</a> | |||
<a class="item" data-tab="third{{$k}}" onclick="loadModelFile({{.VersionName}},'','','init')">模型下载</a> | |||
</div> | |||
<div class="ui tab" data-tab="first"> | |||
<div class="ui tab active" data-tab="first{{$k}}"> | |||
<div style="padding-top: 10px;"> | |||
<div class="tab_2_content"> | |||
<div class="ac-grid ac-grid-col2"> | |||
@@ -159,7 +226,7 @@ td, th { | |||
<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"> | |||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||
任务名称 | |||
</td> | |||
@@ -170,24 +237,68 @@ td, th { | |||
</td> | |||
</tr> | |||
<tr class="ti-no-ng-animate"> | |||
<td class="ti-no-ng-animate ti-text-form-label"> | |||
状态 | |||
</td> | |||
<td class="ti-text-form-content"> | |||
<div class="text-span text-span-w"> | |||
{{.Status}} | |||
</div> | |||
</td> | |||
<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}}-status"> | |||
{{.Status}} | |||
</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"> | |||
{{.VersionName}} | |||
</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"> | |||
<span style="font-size: 12px;" class="">{{TimeSinceUnix .Cloudbrain.CreatedUnix $.Lang}}</span> | |||
</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}}-duration"> | |||
{{.TrainJobDuration}} | |||
</div> | |||
</td> | |||
</tr> | |||
<tr class="ti-no-ng-animate"> | |||
<td class="ti-no-ng-animate ti-text-form-label"> | |||
开始时间 | |||
<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"> | |||
aaa | |||
{{.FlavorName}} | |||
</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"> | |||
{{.WorkServerNumber}} | |||
</div> | |||
</td> | |||
</tr> | |||
@@ -198,35 +309,79 @@ td, th { | |||
<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"> | |||
作业名称 | |||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||
AI引擎 | |||
</td> | |||
<td class="ti-text-form-content"> | |||
<div class="text-span text-span-w"> | |||
trainjob-d672 | job15b681bc | |||
{{.EngineName}} | |||
</div> | |||
</td> | |||
</tr> | |||
<tr class="ti-no-ng-animate"> | |||
<td class="ti-no-ng-animate ti-text-form-label"> | |||
作业名称 | |||
</td> | |||
<td class="ti-text-form-content"> | |||
<div class="text-span text-span-w"> | |||
trainjob-d672 | job15b681bc | |||
</div> | |||
</td> | |||
<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"> | |||
作业名称 | |||
<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"> | |||
trainjob-d672 | job15b681bc | |||
{{.BootFile}} | |||
</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"> | |||
{{.DatasetName}} | |||
</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"> | |||
{{.Parameters}} | |||
</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"> | |||
{{.TrainUrl}} | |||
</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"> | |||
<!-- {{.TrainUrl}} --> | |||
</div> | |||
</td> | |||
</tr> | |||
@@ -238,30 +393,41 @@ td, th { | |||
</div> | |||
</div> | |||
<div class="ui tab" data-tab="second"> | |||
<div class="ui tab" data-tab="second{{$k}}"> | |||
<div> | |||
<div class="ui message" style="display: none;"> | |||
<div class="header"></div> | |||
<div class="ui message{{.VersionName}}" style="display: none;"> | |||
<div id="header"></div> | |||
</div> | |||
<div class="ui top attached segment" style="background: #f0f0f0;"> | |||
<div class="center aligned"> | |||
<label>{{$.i18n.Tr "repo.modelarts.log"}}:</label> | |||
<!-- <span class="fitted file_name"></span> | |||
<input type="hidden" name="file_name" value> | |||
<!-- <span class="fitted file_name">{{.}}</span> --> | |||
<!-- <input type="hidden" name="file_name" value> | |||
<input type="hidden" name="start_line" value> | |||
<input type="hidden" name="end_line" value> --> | |||
</div> | |||
</div> | |||
<div class="ui attached segment log" style="height: 300px !important; overflow: auto;"> | |||
<pre></pre> | |||
<div class="ui attached segment log" onscroll="logScroll({{.VersionName}})" id="log{{.VersionName}}" style="height: 300px !important; overflow: auto;"> | |||
<!-- <input type="hidden" class="version_name" name="version_name" value={{.VersionName}}> --> | |||
<input type="hidden" name="end_line" value> | |||
<input type="hidden" name="start_line" value> | |||
<pre id="log_file{{.VersionName}}"></pre> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="ui tab" data-tab="third"> | |||
<div class="content-pad"> | |||
asdasd | |||
<div class="ui tab" data-tab="third{{$k}}"> | |||
<input type="hidden" name="model{{.VersionName}}" value="-1"> | |||
<input type="hidden" name="modelback{{.VersionName}}" value="-1"> | |||
<div class='ui breadcrumb model_file_bread' id='file_breadcrumb{{.VersionName}}'> | |||
<div class="active section">{{.VersionName}}</div> | |||
<div class="divider"> / </div> | |||
</div> | |||
<div id="dir_list{{.VersionName}}"> | |||
</div> | |||
</div> | |||
@@ -270,18 +436,37 @@ td, th { | |||
</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({{.version_list_task}}) | |||
$('.menu .item').tab() | |||
// $('.ui.style.accordion').accordion(); | |||
// $(document).ready(function(){ | |||
// $('.ui.accordion').accordion({selector:{trigger:'.icon'}}); | |||
// }); | |||
$(document).ready(function(){ | |||
$('.ui.accordion').accordion({selector:{trigger:'.icon'}}); | |||
}); | |||
$(document).ready(function(){ | |||
$('.secondary.menu .item').tab(); | |||
}); | |||
@@ -296,46 +481,246 @@ td, th { | |||
repoPath = urlArr.slice(-4)[0] | |||
jobID = urlArr.slice(-1)[0] | |||
}) | |||
$(".log").scroll(function () { | |||
var scrollTop = $(this)[0].scrollTop; // 滚动距离 | |||
var scrollHeight = $(this)[0].scrollHeight; // 文档高度 | |||
var divHeight = $(this).height(); // 可视区高度 | |||
var file_name = $('input[name=file_name]').val() | |||
function stopBubbling(e) { | |||
e = window.event || e; | |||
if (e.stopPropagation) { | |||
e.stopPropagation(); //阻止事件 冒泡传播 | |||
} else { | |||
e.cancelBubble = true; //ie兼容 | |||
} | |||
} | |||
// var timeid = window.setInterval(refreshStatus(version_name), 30000); | |||
// document.ready(refreshStatus(version_name)) | |||
var timeid = window.setInterval(loadJobStatus, 30000); | |||
$(document).ready(loadJobStatus); | |||
function loadJobStatus() { | |||
$(".ui.accordion.border-according").each((index, job) => { | |||
const jobID = job.dataset.jobid; | |||
const repoPath = job.dataset.repopath; | |||
const versionname = job.dataset.version | |||
if (job.textContent.trim() == 'IMAGE_FAILED' || job.textContent.trim() == 'SUBMIT_FAILED' || job.textContent.trim() == 'DELETE_FAILED' | |||
|| job.textContent.trim() == 'KILLED' || job.textContent.trim() == 'COMPLETED' || job.textContent.trim() == 'FAILED' | |||
|| job.textContent.trim() == 'CANCELED' || job.textContent.trim() == 'LOST') { | |||
return | |||
} | |||
$.get(`/api/v1/repos/${repoPath}/modelarts/train-job/${jobID}?version_name=${versionname}`, (data) => { | |||
// const jobID = data.JobID | |||
// const status = data.JobStatus | |||
// const duration = data.JobDuration | |||
$(`#${versionname}-duration-span`).text(data.JobDuration) | |||
$(`#${versionname}-status-span span`).text(data.JobStatus) | |||
$(`#${versionname}-status-span i`).attr("class",data.JobStatus) | |||
// detail status and duration | |||
$('#'+versionname+'-duration').text(data.JobDuration) | |||
$('#'+versionname+'-status').text(data.JobStatus) | |||
// $('#duration-'+jobID).text(duration) | |||
// if (status != job.textContent.trim()) { | |||
// $('#' + jobID+'-icon').removeClass().addClass(status) | |||
// $('#' + jobID+ '-text').text(status) | |||
// } | |||
}).fail(function(err) { | |||
console.log(err); | |||
}); | |||
}); | |||
}; | |||
function refreshStatus(version_name){ | |||
$.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}?version_name=${version_name}`,(data)=>{ | |||
console.log(data) | |||
// header status and duration | |||
$(`#${version_name}-duration-span`).text(data.JobDuration) | |||
$(`#${version_name}-status-span span`).text(data.JobStatus) | |||
$(`#${version_name}-status-span i`).attr("class",data.JobStatus) | |||
// detail status and duration | |||
$('#'+version_name+'-duration').text(data.JobDuration) | |||
$('#'+version_name+'-status').text(data.JobStatus) | |||
if(parseInt(scrollTop) + divHeight + 29 == scrollHeight){ | |||
var end_line = $('input[name=end_line]').val() | |||
$.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?file_name=${file_name}&base_line=${end_line}&order=desc`, (data) => { | |||
if (data.lines == 0){ | |||
$('.header').text('您已翻阅至日志底部') | |||
$('.message').css('display', 'block') | |||
}).fail(function(err) { | |||
console.log(err); | |||
}); | |||
stopBubbling(arguments.callee.caller.arguments[0]) | |||
} | |||
function deleteVersion(version_name){ | |||
stopBubbling(arguments.callee.caller.arguments[0]) | |||
let flag = 1; | |||
$('.ui.basic.modal').modal({ | |||
onDeny: function() { | |||
flag = false | |||
}, | |||
onApprove: function() { | |||
$.post(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/del_version`,{version_name:version_name},(data)=>{ | |||
$('#accordion'+version_name).remove() | |||
}).fail(function(err) { | |||
console.log(err); | |||
}); | |||
flag = true | |||
}, | |||
onHidden: function() { | |||
if (flag == false) { | |||
$('.alert').html('您已取消操作').removeClass('alert-success').addClass('alert-danger').show().delay(1500).fadeOut(); | |||
} | |||
} | |||
}) | |||
.modal('show') | |||
} | |||
function stopVersion(version_name){ | |||
stopBubbling(arguments.callee.caller.arguments[0]) | |||
$.post(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/stop_version`,{version_name:version_name},(data)=>{ | |||
if(data.StatusOK===0){ | |||
$('#'+version_name+'-stop').addClass('disabled') | |||
refreshStatus(version_name) | |||
} | |||
}).fail(function(err) { | |||
console.log(err); | |||
}); | |||
} | |||
function loadLog(version_name){ | |||
$.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?version_name=${version_name}&lines=20&order=asc`, (data) => { | |||
$('input[name=end_line]').val(data.EndLine) | |||
$('input[name=start_line]').val(data.StartLine) | |||
$(`#log_file${version_name}`).text(data.Content) | |||
}).fail(function(err) { | |||
console.log(err); | |||
}); | |||
} | |||
function loadModelFile(version_name,parents,filename,init){ | |||
parents = parents || '' | |||
filename = filename || '' | |||
init = init || '' | |||
$.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/model_list?version_name=${version_name}&parentDir=${parents}`, (data) => { | |||
$(`#dir_list${version_name}`).empty() | |||
renderDir(data,version_name) | |||
if(init==="init"){ | |||
$(`input[name=model${version_name}]`).val("") | |||
$(`input[name=modelback${version_name}]`).val(version_name) | |||
$(`#file_breadcrumb${version_name}`).empty() | |||
let htmlBread = "" | |||
htmlBread += `<div class='active section'>${version_name}</div>` | |||
htmlBread += "<div class='divider'> / </div>" | |||
$(`#file_breadcrumb${version_name}`).append(htmlBread) | |||
}else{ | |||
renderBrend(version_name,parents,filename,init) | |||
} | |||
}).fail(function(err) { | |||
console.log(err,version_name); | |||
}); | |||
} | |||
function renderBrend(version_name,parents,filename,init){ | |||
if(init=="folder"){ | |||
let htmlBrend = "" | |||
let sectionName=$(`#file_breadcrumb${version_name} .active.section`).text() | |||
let parents1 = $(`input[name=model${version_name}]`).val() | |||
let filename1 = $(`input[name=modelback${version_name}]`).val() | |||
if(parents1===""){ | |||
$(`#file_breadcrumb${version_name} .active.section`).replaceWith(`<a class='section' onclick="loadModelFile('${version_name}','${parents1}','','init')">${sectionName}</a>`) | |||
}else{ | |||
$(`#file_breadcrumb${version_name} .active.section`).replaceWith(`<a class='section' onclick="loadModelFile('${version_name}','${parents1}','${filename1}')">${sectionName}</a>`) | |||
} | |||
htmlBrend += `<div class='active section'>${filename}</div>` | |||
htmlBrend += "<div class='divider'> / </div>" | |||
$(`#file_breadcrumb${version_name}`).append(htmlBrend) | |||
$(`input[name=model${version_name}]`).val(parents) | |||
$(`input[name=modelback${version_name}]`).val(filename) | |||
}else{ | |||
$(`input[name=model${version_name}]`).val(parents) | |||
$(`input[name=modelback${version_name}]`).val(filename) | |||
$(`#file_breadcrumb${version_name} a.section:contains(${filename})`).nextAll().remove() | |||
$(`#file_breadcrumb${version_name} a.section:contains(${filename})`).replaceWith(`<div class='active section'>${filename}</div>`) | |||
$(`#file_breadcrumb${version_name} div.section:contains(${filename})`).append("<div class='divider'> / </div>") | |||
} | |||
} | |||
function renderDir(data,version_name){ | |||
let html="" | |||
html += "<div class='ui grid' style='margin:0;'>" | |||
html += "<div class='row' style='padding: 0;'>" | |||
html += "<div class='ui sixteen wide column' style='padding:1rem;'>" | |||
html += "<div class='dir list'>" | |||
html += "<table id='repo-files-table' class='ui single line table pad20'>" | |||
html += '<tbody>' | |||
// html += "</tbody>" | |||
for(let i=0;i<data.Dirs.length;i++){ | |||
html += "<tr>" | |||
html += "<td class='name six wid'>" | |||
html += "<span class='truncate'>" | |||
html += "<span class='octicon octicon-file-directory'>" | |||
html += "</span>" | |||
if(data.Dirs[i].IsDir){ | |||
html += `<a onclick="loadModelFile('${version_name}','${data.Dirs[i].ParenDir}','${data.Dirs[i].FileName}','folder')">` | |||
html += "<span class='fitted'><i class='folder icon' width='16' height='16' aria-hidden='true'></i>" + data.Dirs[i].FileName + "</span>" | |||
}else{ | |||
html += `<a href='${location.href}/download_model?parentDir=&fileName=${data.Dirs[i].FileName}&jobName=${data.task.JobName}'>` | |||
html += "<span class='fitted'><i class='file icon' width='16' height='16' aria-hidden='true'></i>" + data.Dirs[i].FileName + "</span>" | |||
} | |||
html += '</a>' | |||
html += "</span>" | |||
html += "</td>" | |||
html += "<td class='message seven wide'>" | |||
html += "<span class='truncate has-emoji'>" + data.Dirs[i].Size + "</span>" | |||
html += "</td>" | |||
html += "<td class='text right age three wide'>" | |||
html += "<span class='truncate has-emoji'>" + data.Dirs[i].ModTime + "</span>" | |||
html += "</td>" | |||
html += "</tr>" | |||
} | |||
html += "</tbody>" | |||
html += "</table>" | |||
html += "</div>" | |||
html += "</div>" | |||
html += "</div>" | |||
html += "</div>" | |||
$(`#dir_list${version_name}`).append(html) | |||
} | |||
// $(`.log{}`).scroll() | |||
function logScroll(version_name) { | |||
var scrollTop = $(`#log${version_name}`)[0].scrollTop; // 滚动距离 | |||
var scrollHeight = $(`#log${version_name}`)[0].scrollHeight; // 文档高度 | |||
var divHeight = $(`#log${version_name}`).height(); // 可视区高度 | |||
// let version_name=$(this).find('input[name=version_name]').val() | |||
console.log("scrollTo,scrollHeight,divHeight",scrollTop,scrollHeight,divHeight) | |||
if(parseInt(scrollTop) + divHeight + 18 == scrollHeight){ | |||
var end_line = $(`#log${version_name} input[name=end_line]`).val() | |||
$.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?version_name=${version_name}&base_line=${end_line}&order=desc`, (data) => { | |||
if (data.Lines == 0){ | |||
$(`.message${version_name} #header`).text('您已翻阅至日志底部') | |||
$(`.message${version_name}`).css('display', 'block') | |||
setTimeout(function(){ | |||
$('.message').css('display', 'none') | |||
$(`.message${version_name}`).css('display', 'none') | |||
}, 1000) | |||
}else{ | |||
$('input[name=end_line]').val(data.EndLine) | |||
$('.log').append('<pre>' + data.Content) | |||
$(`#log${version_name} input[name=end_line]`).val(data.EndLine) | |||
$(`#log${version_name}`).append('<pre>' + data.Content) | |||
} | |||
}).fail(function(err) { | |||
console.log(err); | |||
}); | |||
} | |||
if(scrollTop == 0){ | |||
var start_line = $('input[name=start_line]').val() | |||
$.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?file_name=${file_name}&base_line=${start_line}&order=asc`, (data) => { | |||
if (data.lines == 0){ | |||
$('.header').text('您已翻阅至日志顶部') | |||
$('.message').css('display', 'block') | |||
var start_line = $(`#log${version_name} input[name=start_line]`).val() | |||
$.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?version_name=${version_name}&base_line=${start_line}&order=asc`, (data) => { | |||
if (data.Lines == 0){ | |||
$(`.message${version_name} #header`).text('您已翻阅至日志顶部') | |||
$(`.message${version_name}`).css('display', 'block') | |||
setTimeout(function(){ | |||
$('.message').css('display', 'none') | |||
$(`.message${version_name}`).css('display', 'none') | |||
}, 1000) | |||
}else{ | |||
$('input[name=start_line]').val(data.StartLine) //如果变动就改变所对应的值 | |||
$(".log").prepend('<pre>' + data.Content) | |||
$(`#log${version_name} input[name=start_line]`).val(data.StartLine) //如果变动就改变所对应的值 | |||
$(`#log${version_name}`).prepend('<pre>' + data.Content) | |||
} | |||
}).fail(function(err) { | |||
console.log(err); | |||
}); | |||
} | |||
}) | |||
} | |||
</script> |
@@ -156,12 +156,20 @@ | |||
<form class="ui form" action="{{$.RepoLink}}/modelarts/train-job/{{.JobID}}/create_version" method="post"> | |||
{{.CsrfTokenHtml}} | |||
<input type="hidden" name="action" value="update"> | |||
<input type="hidden" name="version_name" value=""> | |||
<input type="hidden" id="ai_engine_name" name="engine_names" value=""> | |||
<input type="hidden" id="ai_flaver_name" name="flaver_names" value=""> | |||
<h4 class="unite title ui header ">{{.i18n.Tr "repo.modelarts.train_job.basic_info"}}:</h4> | |||
<div class="required unite min_title inline field"> | |||
<label>{{.i18n.Tr "repo.modelarts.train_job.job_name"}}</label> | |||
<input type="hidden" style="width: 60%;" name="job_name" id="trainjob_job_name" value="{{.job_name}}"> | |||
<input style="width: 60%;" value="{{.job_name}}" tabindex="3" disabled > | |||
</div> | |||
<div class="required unite min_title inline field"> | |||
<label>{{.i18n.Tr "repo.modelarts.parents_version"}}</label> | |||
<input id="parents_version" style="width: 60%;" value="" tabindex="3" disabled > | |||
</div> | |||
<div class="unite min_title inline field"> | |||
<label for="description">{{.i18n.Tr "repo.modelarts.train_job.description"}} </label> | |||
<textarea style="width: 80%;" id="description" value="{{.description}}" name="description" rows="3" maxlength="255" placeholder={{.i18n.Tr "repo.modelarts.train_job.new_place"}} onchange="this.value=this.value.substring(0, 255)" onkeydown="this.value=this.value.substring(0, 255)" onkeyup="this.value=this.value.substring(0, 256)"></textarea> | |||
@@ -198,7 +206,7 @@ | |||
</select> | |||
</div> | |||
<div class="field" style="flex: 2;"> | |||
<div class="field" style="flex: 2;" id="engine_name"> | |||
<select class="ui dropdown width" id="trainjob_engine_versions" style='width: 100%;' name="engine_id"> | |||
{{if .engine_id}} | |||
<option name="engine_id" value="{{.engine_id}}">{{.engine_name}}</option> | |||
@@ -290,7 +298,7 @@ | |||
</div> | |||
</div> | |||
<div class="required unite min_title inline field"> | |||
<div class="required unite min_title inline field" id="flaver_name"> | |||
<label>{{.i18n.Tr "repo.modelarts.train_job.standard"}}</label> | |||
<select class="ui dropdown width81" id="trainjob-flavor" style='width:385px' name="flavor"> | |||
{{if .flavor_name}} | |||
@@ -331,9 +339,12 @@ | |||
<script> | |||
let url_href = {{.RepoLink}}+'/modelarts/train-job' | |||
let url_post = window.location.pathname.split('?version_name=V0001')[0] | |||
let url_post = location.pathname | |||
let version_name = location.search.split('?version_name=')[1] | |||
$("#parents_version").val(version_name) | |||
$(".ui.button").attr('href',url_href) | |||
$(".ui.form").attr('action',url_post) | |||
$("input[name=version_name]").attr('value',version_name) | |||
$('select.dropdown') | |||
.dropdown(); | |||
@@ -582,8 +593,18 @@ | |||
msg = JSON.stringify(msg) | |||
$('#store_run_para').val(msg) | |||
} | |||
function get_name(){ | |||
console.log("--------------") | |||
let name1=$("#engine_name .text").text() | |||
let name2=$("#flaver_name .text").text() | |||
console.log(name1,name2) | |||
$("input#ai_engine_name").val(name1) | |||
$("input#ai_flaver_name").val(name2) | |||
} | |||
$('.ui.create_train_job.green.button').click(function(e) { | |||
get_name() | |||
send_run_para() | |||
validate() | |||
}) |
@@ -2785,67 +2785,6 @@ $(document).ready(async () => { | |||
} | |||
}); | |||
} | |||
// dataset Dropzone | |||
// const $dataset = $('#dataset'); | |||
// if ($dataset.length > 0) { | |||
// const filenameDict = {}; | |||
// let previewTemplate = ''; | |||
// previewTemplate += '<div class="dz-preview dz-file-preview">\n '; | |||
// previewTemplate += ' <div class="dz-details">\n '; | |||
// previewTemplate += ' <div class="dz-filename">'; | |||
// previewTemplate += ' <span data-dz-name data-dz-thumbnail></span>'; | |||
// previewTemplate += ' </div>\n '; | |||
// previewTemplate += ' <div class="dz-size" data-dz-size></div>\n '; | |||
// previewTemplate += ' </div>\n '; | |||
// previewTemplate += ' <div class="dz-progress ui active progress">'; | |||
// previewTemplate += ' <div class="dz-upload bar" data-dz-uploadprogress><div class="progress"></div></div>\n '; | |||
// previewTemplate += ' </div>\n '; | |||
// previewTemplate += ' <div class="dz-success-mark">'; | |||
// previewTemplate += ' <span>上传成功</span>'; | |||
// previewTemplate += ' </div>\n '; | |||
// previewTemplate += ' <div class="dz-error-mark">'; | |||
// previewTemplate += ' <span>上传失败</span>'; | |||
// previewTemplate += ' </div>\n '; | |||
// previewTemplate += ' <div class="dz-error-message">'; | |||
// previewTemplate += ' <span data-dz-errormessage></span>'; | |||
// previewTemplate += ' </div>\n'; | |||
// previewTemplate += '</div>'; | |||
// await createDropzone('#dataset', { | |||
// url: $dataset.data('upload-url'), | |||
// headers: {'X-Csrf-Token': csrf}, | |||
// maxFiles: $dataset.data('max-file'), | |||
// maxFilesize: $dataset.data('max-size'), | |||
// acceptedFiles: ($dataset.data('accepts') === '*/*') ? null : $dataset.data('accepts'), | |||
// addRemoveLinks: true, | |||
// timeout: 0, | |||
// dictDefaultMessage: $dataset.data('default-message'), | |||
// dictInvalidFileType: $dataset.data('invalid-input-type'), | |||
// dictFileTooBig: $dataset.data('file-too-big'), | |||
// dictRemoveFile: $dataset.data('remove-file'), | |||
// previewTemplate, | |||
// init() { | |||
// this.on('success', (file, data) => { | |||
// filenameDict[file.name] = data.uuid; | |||
// const input = $(`<input id="${data.uuid}" name="files" type="hidden">`).val(data.uuid); | |||
// $('.files').append(input); | |||
// }); | |||
// this.on('removedfile', (file) => { | |||
// if (file.name in filenameDict) { | |||
// $(`#${filenameDict[file.name]}`).remove(); | |||
// } | |||
// if ($dataset.data('remove-url') && $dataset.data('csrf')) { | |||
// $.post($dataset.data('remove-url'), { | |||
// file: filenameDict[file.name], | |||
// _csrf: $dataset.data('csrf') | |||
// }); | |||
// } | |||
// }); | |||
// }, | |||
// }); | |||
// } | |||
// Helpers. | |||
$('.delete-button').on('click', showDeletePopup); | |||
$('.add-all-button').on('click', showAddAllPopup); | |||
@@ -3984,243 +3923,6 @@ function initNavbarContentToggle() { | |||
}); | |||
} | |||
// function initTopicbar() { | |||
// const mgrBtn = $('#manage_topic'); | |||
// const editDiv = $('#topic_edit'); | |||
// const viewDiv = $('#repo-topics'); | |||
// const saveBtn = $('#save_topic'); | |||
// const topicDropdown = $('#topic_edit .dropdown'); | |||
// const topicForm = $('#topic_edit.ui.form'); | |||
// const topicInput = $("#topics_input") | |||
// const topicPrompts = getPrompts(); | |||
// mgrBtn.on('click', (e) => { | |||
// // viewDiv.hide(); | |||
// editDiv.css('display', ''); // show Semantic UI Grid | |||
// topicInput.val('') | |||
// console.log("-----------------asdasd",$("#topics_input"),$("#topics_input").val()) | |||
// stopPropagation(e); | |||
// }); | |||
// $(document).bind('click',function(){ | |||
// editDiv.css('display','none'); | |||
// }) | |||
// editDiv.click(function(e){ | |||
// stopPropagation(e); | |||
// }) | |||
// function getPrompts() { | |||
// const hidePrompt = $('div.hide#validate_prompt'); | |||
// const prompts = { | |||
// countPrompt: hidePrompt.children('#count_prompt').text(), | |||
// formatPrompt: hidePrompt.children('#format_prompt').text() | |||
// }; | |||
// hidePrompt.remove(); | |||
// return prompts; | |||
// } | |||
// function stopPropagation(e) { | |||
// var ev = e || window.event; | |||
// if (ev.stopPropagation) { | |||
// ev.stopPropagation(); | |||
// } | |||
// else if (window.event) { | |||
// window.event.cancelBubble = true;//兼容IE | |||
// } | |||
// } | |||
// saveBtn.on('click', () => { | |||
// const topics = $('input[name=topics]').val(); | |||
// $.post( | |||
// saveBtn.data('link'), | |||
// { | |||
// _csrf: csrf, | |||
// topics | |||
// }, | |||
// (_data, _textStatus, xhr) => { | |||
// if (xhr.responseJSON.status === 'ok') { | |||
// console.log("--------saveBtn------------") | |||
// viewDiv.children('.topic').remove(); | |||
// if (topics.length) { | |||
// const topicArray = topics.split(','); | |||
// const last = viewDiv.children('a').last(); | |||
// for (let i = 0; i < topicArray.length; i++) { | |||
// const link = $('<a class="ui repo-topic small label topic"></a>'); | |||
// link.attr( | |||
// 'href', | |||
// `${AppSubUrl}/explore/repos?q=${encodeURIComponent( | |||
// topicArray[i] | |||
// )}&topic=1` | |||
// ); | |||
// link.text(topicArray[i]); | |||
// link.insertBefore(last); | |||
// } | |||
// } | |||
// editDiv.css('display', 'none'); | |||
// viewDiv.show(); | |||
// } | |||
// } | |||
// ) | |||
// .fail((xhr) => { | |||
// if (xhr.status === 422) { | |||
// if (xhr.responseJSON.invalidTopics.length > 0) { | |||
// topicPrompts.formatPrompt = xhr.responseJSON.message; | |||
// const {invalidTopics} = xhr.responseJSON; | |||
// const topicLables = topicDropdown.children('a.ui.label'); | |||
// topics.split(',').forEach((value, index) => { | |||
// for (let i = 0; i < invalidTopics.length; i++) { | |||
// if (invalidTopics[i] === value) { | |||
// topicLables | |||
// .eq(index) | |||
// .removeClass('green') | |||
// .addClass('red'); | |||
// } | |||
// } | |||
// }); | |||
// } else { | |||
// topicPrompts.countPrompt = xhr.responseJSON.message; | |||
// } | |||
// } | |||
// }) | |||
// .always(() => { | |||
// topicForm.form('validate form'); | |||
// }); | |||
// }); | |||
// topicDropdown.dropdown({ | |||
// allowAdditions: true, | |||
// forceSelection: false, | |||
// fields: {name: 'description', value: 'data-value'}, | |||
// saveRemoteData: false, | |||
// label: { | |||
// transition: 'horizontal flip', | |||
// duration: 200, | |||
// variation: false, | |||
// blue: true, | |||
// basic: true | |||
// }, | |||
// className: { | |||
// label: 'ui small label' | |||
// }, | |||
// apiSettings: { | |||
// url: `${AppSubUrl}/api/v1/topics/search?q={query}`, | |||
// throttle: 500, | |||
// cache: false, | |||
// onResponse(res) { | |||
// const formattedResponse = { | |||
// success: false, | |||
// results: [] | |||
// }; | |||
// const stripTags = function (text) { | |||
// return text.replace(/<[^>]*>?/gm, ''); | |||
// }; | |||
// const query = stripTags(this.urlData.query.trim()); | |||
// let found_query = false; | |||
// const current_topics = []; | |||
// topicDropdown | |||
// .find('div.label.visible.topic,a.label.visible') | |||
// .each((_, e) => { | |||
// current_topics.push(e.dataset.value); | |||
// }); | |||
// if (res.topics) { | |||
// let found = false; | |||
// for (let i = 0; i < res.topics.length; i++) { | |||
// // skip currently added tags | |||
// if (current_topics.includes(res.topics[i].topic_name)) { | |||
// continue; | |||
// } | |||
// if ( | |||
// res.topics[i].topic_name.toLowerCase() === query.toLowerCase() | |||
// ) { | |||
// found_query = true; | |||
// } | |||
// formattedResponse.results.push({ | |||
// description: res.topics[i].topic_name, | |||
// 'data-value': res.topics[i].topic_name | |||
// }); | |||
// found = true; | |||
// } | |||
// formattedResponse.success = found; | |||
// } | |||
// if (query.length > 0 && !found_query) { | |||
// formattedResponse.success = true; | |||
// formattedResponse.results.unshift({ | |||
// description: query, | |||
// 'data-value': query | |||
// }); | |||
// } else if (query.length > 0 && found_query) { | |||
// formattedResponse.results.sort((a, b) => { | |||
// if (a.description.toLowerCase() === query.toLowerCase()) return -1; | |||
// if (b.description.toLowerCase() === query.toLowerCase()) return 1; | |||
// if (a.description > b.description) return -1; | |||
// if (a.description < b.description) return 1; | |||
// return 0; | |||
// }); | |||
// } | |||
// return formattedResponse; | |||
// } | |||
// }, | |||
// onLabelCreate(value) { | |||
// value = value.toLowerCase().trim(); | |||
// this.attr('data-value', value) | |||
// .contents() | |||
// .first() | |||
// .replaceWith(value); | |||
// return $(this); | |||
// }, | |||
// onAdd(addedValue, _addedText, $addedChoice) { | |||
// addedValue = addedValue.toLowerCase().trim(); | |||
// $($addedChoice).attr('data-value', addedValue); | |||
// $($addedChoice).attr('data-text', addedValue); | |||
// } | |||
// }); | |||
// $.fn.form.settings.rules.validateTopic = function (_values, regExp) { | |||
// const topics = topicDropdown.children('a.ui.label'); | |||
// const status = | |||
// topics.length === 0 || (topics.last().attr('data-value').match(regExp) !== null && topics.last().attr('data-value').length <= 35); | |||
// if (!status) { | |||
// topics | |||
// .last() | |||
// .removeClass('green') | |||
// .addClass('red'); | |||
// } | |||
// return status && topicDropdown.children('a.ui.label.red').length === 0; | |||
// }; | |||
// topicForm.form({ | |||
// on: 'change', | |||
// inline: true, | |||
// fields: { | |||
// topics: { | |||
// identifier: 'topics', | |||
// rules: [ | |||
// { | |||
// type: 'validateTopic', | |||
// value: /^[\u4e00-\u9fa5a-z0-9][\u4e00-\u9fa5a-z0-9-]{0,105}$/, | |||
// prompt: topicPrompts.formatPrompt | |||
// }, | |||
// { | |||
// type: 'maxCount[25]', | |||
// prompt: topicPrompts.countPrompt | |||
// } | |||
// ] | |||
// } | |||
// } | |||
// }); | |||
// } | |||
window.toggleDeadlineForm = function () { | |||
$('#deadlineForm').fadeToggle(150); | |||