@@ -1470,7 +1470,7 @@ type GetNotebookListResult struct { | |||
NotebookList []NotebookList `json:"data"` | |||
} | |||
//Grampus | |||
// Grampus | |||
type GrampusResult struct { | |||
ErrorCode int `json:"errorCode"` | |||
ErrorMsg string `json:"errorMsg"` | |||
@@ -1859,7 +1859,7 @@ func QueryModelTrainJobList(repoId int64) ([]*Cloudbrain, int, error) { | |||
// ) | |||
cloudbrains := make([]*Cloudbrain, 0) | |||
if err := sess.Select("job_id,display_job_name").Table(&Cloudbrain{}).Where(cond).OrderBy("created_unix DESC"). | |||
if err := sess.Select("*").Table(&Cloudbrain{}).Where(cond).OrderBy("created_unix DESC"). | |||
Find(&cloudbrains); err != nil { | |||
return nil, 0, fmt.Errorf("Find: %v", err) | |||
} | |||
@@ -2200,8 +2200,10 @@ func GetGPUStoppedNotDebugJobDaysAgo(days int, limit int) ([]*Cloudbrain, error) | |||
Find(&cloudbrains) | |||
} | |||
/** | |||
本方法考虑了再次调试的情况,多次调试取最后一次的任务的结束时间 | |||
/* | |||
* | |||
本方法考虑了再次调试的情况,多次调试取最后一次的任务的结束时间 | |||
*/ | |||
func GetGPUStoppedDebugJobDaysAgo(days int, limit int) ([]*Cloudbrain, error) { | |||
cloudbrains := make([]*Cloudbrain, 0, 10) | |||
@@ -2663,7 +2665,7 @@ type DatasetInfo struct { | |||
Name string | |||
FullName string | |||
Type int | |||
Size int | |||
Size int64 | |||
} | |||
func GetDatasetInfo(uuidStr string, grampusType ...string) (map[string]DatasetInfo, string, error) { | |||
@@ -2726,7 +2728,7 @@ func GetDatasetInfo(uuidStr string, grampusType ...string) (map[string]DatasetIn | |||
Name: fileName, | |||
FullName: attach.Name, | |||
Type: attach.Type, | |||
Size: int(attach.Size), | |||
Size: attach.Size, | |||
} | |||
if i == 0 { | |||
datasetNames = attach.Name | |||
@@ -330,7 +330,7 @@ func QueryUserStaticDataForUserDefine(opts *UserBusinessAnalysisQueryOptions, wi | |||
DataDate := currentTimeNow.Format("2006-01-02 15:04") | |||
CodeMergeCountMap := queryPullRequest(start_unix, end_unix) | |||
CommitCountMap, _ := queryCommitAction(start_unix, end_unix, 5) | |||
CommitCountMap := queryCommitAction(start_unix, end_unix, 5) | |||
IssueCountMap := queryCreateIssue(start_unix, end_unix) | |||
CommentCountMap := queryComment(start_unix, end_unix) | |||
@@ -586,7 +586,7 @@ func refreshUserStaticTable(wikiCountMap map[string]int, tableName string, pageS | |||
startTime := currentTimeNow.AddDate(0, 0, -1) | |||
CodeMergeCountMap := queryPullRequest(start_unix, end_unix) | |||
CommitCountMap, _ := queryCommitAction(start_unix, end_unix, 5) | |||
CommitCountMap := queryCommitAction(start_unix, end_unix, 5) | |||
IssueCountMap := queryCreateIssue(start_unix, end_unix) | |||
CommentCountMap := queryComment(start_unix, end_unix) | |||
@@ -762,7 +762,8 @@ func RefreshUserYearTable(pageStartTime time.Time, pageEndTime time.Time) { | |||
end_unix := pageEndTime.Unix() | |||
CodeMergeCountMap := queryPullRequest(start_unix, end_unix) | |||
CommitCountMap, mostActiveMap := queryCommitAction(start_unix, end_unix, 5) | |||
CommitCountMap := queryCommitAction(start_unix, end_unix, 5) | |||
mostActiveMap := queryMostActiveCommitAction(start_unix, end_unix) | |||
IssueCountMap := queryCreateIssue(start_unix, end_unix) | |||
CommentCountMap := queryComment(start_unix, end_unix) | |||
@@ -841,9 +842,9 @@ func RefreshUserYearTable(pageStartTime time.Time, pageEndTime time.Time) { | |||
repoInfo := getRepoDetailInfo(DetailInfoMap, dateRecordAll.ID, MostDownloadMap) | |||
dataSetInfo, datasetscore := getDataSetInfo(dateRecordAll.ID, CreatedDataset, dataSetDownloadMap, CommitDatasetNumMap, CollectedDataset) | |||
scoreMap["datasetscore"] = datasetscore | |||
codeInfo, codescore := getCodeInfo(dateRecordAll) | |||
codeInfo, codescore := getCodeInfo(&dateRecordAll) | |||
scoreMap["codescore"] = codescore | |||
cloudBrainInfo := getCloudBrainInfo(dateRecordAll, CloudBrainTaskItemMap, scoreMap) | |||
cloudBrainInfo := getCloudBrainInfo(&dateRecordAll, CloudBrainTaskItemMap, scoreMap) | |||
playARoll := getPlayARoll(bonusMap, dateRecordAll.Name, scoreMap) | |||
re := &UserSummaryCurrentYear{ | |||
ID: dateRecordAll.ID, | |||
@@ -1027,7 +1028,7 @@ func getPlayARoll(bonusMap map[string]map[string]int, userName string, scoreMap | |||
} | |||
} | |||
func getCloudBrainInfo(dateRecordAll UserBusinessAnalysisAll, CloudBrainTaskItemMap map[string]int, scoreMap map[string]float64) string { | |||
func getCloudBrainInfo(dateRecordAll *UserBusinessAnalysisAll, CloudBrainTaskItemMap map[string]int, scoreMap map[string]float64) string { | |||
trainscore := 0.0 | |||
debugscore := 0.0 | |||
runtime := 0.0 | |||
@@ -1043,6 +1044,7 @@ func getCloudBrainInfo(dateRecordAll UserBusinessAnalysisAll, CloudBrainTaskItem | |||
trainscore = float64(dateRecordAll.GpuTrainJob+dateRecordAll.NpuTrainJob) / float64(50) | |||
} | |||
cloudBrainInfo["inference_task_num"] = fmt.Sprint(dateRecordAll.NpuInferenceJob + CloudBrainTaskItemMap[fmt.Sprint(dateRecordAll.ID)+"_GpuInferenceJob"]) | |||
cloudBrainInfo["benchmark_task_num"] = fmt.Sprint(dateRecordAll.GpuBenchMarkJob) | |||
cloudBrainInfo["card_runtime"] = fmt.Sprint(dateRecordAll.CloudBrainRunTime) | |||
cloudBrainInfo["card_runtime_money"] = fmt.Sprint(dateRecordAll.CloudBrainRunTime * 5) | |||
cloudBrainInfo["CloudBrainOne"] = fmt.Sprint(CloudBrainTaskItemMap[fmt.Sprint(dateRecordAll.ID)+"_CloudBrainOne"]) | |||
@@ -1061,7 +1063,7 @@ func getCloudBrainInfo(dateRecordAll UserBusinessAnalysisAll, CloudBrainTaskItem | |||
} | |||
} | |||
func getCodeInfo(dateRecordAll UserBusinessAnalysisAll) (string, float64) { | |||
func getCodeInfo(dateRecordAll *UserBusinessAnalysisAll) (string, float64) { | |||
if dateRecordAll.CommitCount > 0 { | |||
codeInfo := make(map[string]string) | |||
codeInfo["commit_count"] = fmt.Sprint(dateRecordAll.CommitCount) | |||
@@ -1245,7 +1247,7 @@ func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time, | |||
DataDate := CountDate.Format("2006-01-02") | |||
CodeMergeCountMap := queryPullRequest(start_unix, end_unix) | |||
CommitCountMap, _ := queryCommitAction(start_unix, end_unix, 5) | |||
CommitCountMap := queryCommitAction(start_unix, end_unix, 5) | |||
IssueCountMap := queryCreateIssue(start_unix, end_unix) | |||
CommentCountMap := queryComment(start_unix, end_unix) | |||
@@ -1391,7 +1393,7 @@ func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time, | |||
useMetrics.TotalActivateRegistUser = getMapKeyStringValue("TotalActivateRegistUser", userMetrics) | |||
useMetrics.TotalHasActivityUser = getMapKeyStringValue("TotalHasActivityUser", userMetrics) | |||
useMetrics.CurrentDayRegistUser = getMapKeyStringValue("CurrentDayRegistUser", userMetrics) | |||
count, err = sess.Where("type=0").Count(new(User)) | |||
count, err = sess.Where("type=0 and created_unix<=" + fmt.Sprint(end_unix)).Count(new(User)) | |||
if err != nil { | |||
log.Info("query user error. return.") | |||
} | |||
@@ -1739,52 +1741,48 @@ func queryPullRequest(start_unix int64, end_unix int64) map[int64]int { | |||
return resultMap | |||
} | |||
func queryCommitAction(start_unix int64, end_unix int64, actionType int64) (map[int64]int, map[int64]map[string]int) { | |||
func queryMostActiveCommitAction(start_unix int64, end_unix int64) map[int64]map[string]int { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
resultMap := make(map[int64]int) | |||
mostActiveMap := make(map[int64]map[string]int) | |||
cond := "user_id=act_user_id and created_unix>=" + fmt.Sprint(start_unix) + " and created_unix<=" + fmt.Sprint(end_unix) | |||
count, err := sess.Where(cond).Count(new(Action)) | |||
if err != nil { | |||
log.Info("query action error. return.") | |||
return resultMap, mostActiveMap | |||
return mostActiveMap | |||
} | |||
var indexTotal int64 | |||
indexTotal = 0 | |||
for { | |||
sess.Select("id,user_id,op_type,act_user_id,created_unix").Table("action").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal)) | |||
actionList := make([]*Action, 0) | |||
sess.Find(&actionList) | |||
log.Info("query action size=" + fmt.Sprint(len(actionList))) | |||
actionList, err := sess.QueryInterface("select id,user_id,op_type,act_user_id,created_unix from public.action where " + cond + " order by id asc limit " + fmt.Sprint(PAGE_SIZE) + " offset " + fmt.Sprint(indexTotal)) | |||
if err != nil { | |||
log.Info("error:" + err.Error()) | |||
continue | |||
} | |||
log.Info("query mostactive action size=" + fmt.Sprint(len(actionList))) | |||
for _, actionRecord := range actionList { | |||
if int64(actionRecord.OpType) == actionType { | |||
if _, ok := resultMap[actionRecord.UserID]; !ok { | |||
resultMap[actionRecord.UserID] = 1 | |||
} else { | |||
resultMap[actionRecord.UserID] += 1 | |||
} | |||
} | |||
key := getDate(actionRecord.CreatedUnix) | |||
if _, ok := mostActiveMap[actionRecord.UserID]; !ok { | |||
userId := convertInterfaceToInt64(actionRecord["user_id"]) | |||
created_unix := timeutil.TimeStamp(convertInterfaceToInt64(actionRecord["created_unix"])) | |||
key := getDate(created_unix) | |||
if _, ok := mostActiveMap[userId]; !ok { | |||
tmpMap := make(map[string]int) | |||
tmpMap[key] = 1 | |||
mostActiveMap[actionRecord.UserID] = tmpMap | |||
mostActiveMap[userId] = tmpMap | |||
} else { | |||
mostActiveMap[actionRecord.UserID][key] = getMapKeyStringValue(key, mostActiveMap[actionRecord.UserID]) + 1 | |||
mostActiveMap[userId][key] = getMapKeyStringValue(key, mostActiveMap[userId]) + 1 | |||
} | |||
utcTime := actionRecord.CreatedUnix.AsTime() | |||
utcTime := created_unix.AsTime() | |||
hour := utcTime.Hour() | |||
if hour >= 0 && hour <= 5 { | |||
key = "hour_hour" | |||
if getMapKeyStringValue(key, mostActiveMap[actionRecord.UserID]) < hour { | |||
mostActiveMap[actionRecord.UserID][key] = hour | |||
mostActiveMap[actionRecord.UserID]["hour_day"] = utcTime.Day() | |||
mostActiveMap[actionRecord.UserID]["hour_month"] = int(utcTime.Month()) | |||
mostActiveMap[actionRecord.UserID]["hour_year"] = utcTime.Year() | |||
if getMapKeyStringValue(key, mostActiveMap[userId]) < hour { | |||
mostActiveMap[userId][key] = hour | |||
mostActiveMap[userId]["hour_day"] = utcTime.Day() | |||
mostActiveMap[userId]["hour_month"] = int(utcTime.Month()) | |||
mostActiveMap[userId]["hour_year"] = utcTime.Year() | |||
} | |||
} | |||
} | |||
@@ -1793,9 +1791,60 @@ func queryCommitAction(start_unix int64, end_unix int64, actionType int64) (map[ | |||
break | |||
} | |||
} | |||
return mostActiveMap | |||
} | |||
return resultMap, mostActiveMap | |||
func queryCommitAction(start_unix int64, end_unix int64, actionType int64) map[int64]int { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
resultMap := make(map[int64]int) | |||
cond := "op_type=" + fmt.Sprint(actionType) + " and user_id=act_user_id and created_unix>=" + fmt.Sprint(start_unix) + " and created_unix<=" + fmt.Sprint(end_unix) | |||
count, err := sess.Where(cond).Count(new(Action)) | |||
if err != nil { | |||
log.Info("query action error. return.") | |||
return resultMap | |||
} | |||
var indexTotal int64 | |||
indexTotal = 0 | |||
for { | |||
actionList, err := sess.QueryInterface("select id,user_id,op_type,act_user_id,created_unix from public.action where " + cond + " order by id asc limit " + fmt.Sprint(PAGE_SIZE) + " offset " + fmt.Sprint(indexTotal)) | |||
if err != nil { | |||
log.Info("error:" + err.Error()) | |||
continue | |||
} | |||
log.Info("query action size=" + fmt.Sprint(len(actionList))) | |||
for _, actionRecord := range actionList { | |||
userId := convertInterfaceToInt64(actionRecord["user_id"]) | |||
if _, ok := resultMap[userId]; !ok { | |||
resultMap[userId] = 1 | |||
} else { | |||
resultMap[userId] += 1 | |||
} | |||
} | |||
indexTotal += PAGE_SIZE | |||
if indexTotal >= count { | |||
break | |||
} | |||
} | |||
return resultMap | |||
} | |||
func convertInterfaceToInt64(obj interface{}) int64 { | |||
switch obj.(type) { | |||
case int8: | |||
return int64(obj.(int8)) | |||
case int16: | |||
return int64(obj.(int16)) | |||
case int32: | |||
return int64(obj.(int32)) | |||
case int64: | |||
return obj.(int64) | |||
} | |||
return 0 | |||
} | |||
func getDate(createTime timeutil.TimeStamp) string { | |||
return createTime.Format("2006-01-02") | |||
} | |||
@@ -2488,11 +2537,12 @@ func queryCloudBrainTask(start_unix int64, end_unix int64) (map[int64]int, map[s | |||
resultItemMap := make(map[string]int) | |||
cond := " created_unix>=" + fmt.Sprint(start_unix) + " and created_unix<=" + fmt.Sprint(end_unix) | |||
count, err := sess.Where(cond).Count(new(Cloudbrain)) | |||
count, err := sess.Where(cond).Unscoped().Count(new(Cloudbrain)) | |||
if err != nil { | |||
log.Info("query cloudbrain error. return.") | |||
return resultMap, resultItemMap | |||
} | |||
log.Info("cloudbrain count=" + fmt.Sprint(count)) | |||
var indexTotal int64 | |||
indexTotal = 0 | |||
for { | |||
@@ -2515,6 +2565,8 @@ func queryCloudBrainTask(start_unix int64, end_unix int64) (map[int64]int, map[s | |||
setMapKey("NpuTrainJob", cloudTaskRecord.UserID, 1, resultItemMap) | |||
} else if cloudTaskRecord.JobType == "INFERENCE" { | |||
setMapKey("NpuInferenceJob", cloudTaskRecord.UserID, 1, resultItemMap) | |||
} else if cloudTaskRecord.JobType == "BENCHMARK" || cloudTaskRecord.JobType == "MODELSAFETY" { | |||
setMapKey("GpuBenchMarkJob", cloudTaskRecord.UserID, 1, resultItemMap) | |||
} else { | |||
setMapKey("NpuDebugJob", cloudTaskRecord.UserID, 1, resultItemMap) | |||
} | |||
@@ -2524,7 +2576,7 @@ func queryCloudBrainTask(start_unix int64, end_unix int64) (map[int64]int, map[s | |||
setMapKey("GpuTrainJob", cloudTaskRecord.UserID, 1, resultItemMap) | |||
} else if cloudTaskRecord.JobType == "INFERENCE" { | |||
setMapKey("GpuInferenceJob", cloudTaskRecord.UserID, 1, resultItemMap) | |||
} else if cloudTaskRecord.JobType == "BENCHMARK" { | |||
} else if cloudTaskRecord.JobType == "BENCHMARK" || cloudTaskRecord.JobType == "MODELSAFETY" { | |||
setMapKey("GpuBenchMarkJob", cloudTaskRecord.UserID, 1, resultItemMap) | |||
} else { | |||
setMapKey("GpuDebugJob", cloudTaskRecord.UserID, 1, resultItemMap) | |||
@@ -2551,7 +2603,6 @@ func queryCloudBrainTask(start_unix int64, end_unix int64) (map[int64]int, map[s | |||
break | |||
} | |||
} | |||
return resultMap, resultItemMap | |||
} | |||
@@ -3322,6 +3322,7 @@ Stopped_failed=Fail to stop the job, please try again later. | |||
Stopped_success_update_status_fail=Succeed in stopping th job, but failed to update the job status and duration time. | |||
load_code_failed=Fail to load code, please check if the right branch is selected. | |||
error.debug_datasetsize = The size of dataset exceeds limitation (%dGB) | |||
error.dataset_select = dataset select error:the count exceed the limit or has same name | |||
error.partial_datasets_not_available = There are non-existent or deleted files in the selected dataset file, please select again | |||
new_train_gpu_tooltips = The code is storaged in <strong style="color:#010101">%s</strong>, the dataset is storaged in <strong style="color:#010101">%s</strong>, the pre-trained model is storaged in the run parameter <strong style="color:#010101">%s</strong>, and please put your model into <strong style="color:#010101">%s</strong> then you can download it online | |||
@@ -3343,7 +3343,7 @@ Stopped_failed=任务停止失败,请稍后再试。 | |||
Stopped_success_update_status_fail=任务停止成功,状态及运行时间更新失败。 | |||
load_code_failed=代码加载失败,请确认选择了正确的分支。 | |||
error.debug_datasetsize = 数据集大小超过限制('%d'GB) | |||
error.debug_datasetsize = 数据集大小超过限制(%dGB) | |||
error.dataset_select = 数据集选择错误:数量超过限制或者有同名数据集 | |||
error.partial_datasets_not_available = 选择的数据集文件中有不存在或已删除的文件,请重新选择 | |||
new_train_gpu_tooltips = 训练脚本存储在 <strong style="color:#010101">%s</strong> 中,数据集存储在 <strong style="color:#010101">%s</strong> 中,预训练模型存放在运行参数 <strong style="color:#010101">%s</strong> 中,训练输出请存储在 <strong style="color:#010101">%s</strong> 中以供后续下载。 | |||
@@ -457,7 +457,7 @@ var actionNameZH={ | |||
"37":"提交的镜像 {image} 被设置为推荐镜像", | |||
"39":"创建了CPU/GPU类型调试任务", | |||
"40":"创建了NPU类型调试任务", | |||
"41":"创建了GCU类型训练任务", | |||
"41":"创建了GCU类型调试任务", | |||
}; | |||
var actionNameEN={ | |||
@@ -738,6 +738,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
m.Combo("/repositories/:id", reqToken()).Get(repo.GetByID) | |||
m.Group("/datasets/:username/:reponame", func() { | |||
m.Get("", repo.CurrentRepoDatasetInfoWithoutAttachment) | |||
m.Get("/current_repo", repo.CurrentRepoDatasetMultiple) | |||
m.Get("/my_datasets", repo.MyDatasetsMultiple) | |||
m.Get("/public_datasets", repo.PublicDatasetMultiple) | |||
@@ -51,6 +51,28 @@ func CurrentRepoDatasetMultiple(ctx *context.APIContext) { | |||
} | |||
func CurrentRepoDatasetInfoWithoutAttachment(ctx *context.APIContext) { | |||
dataset, err := models.GetDatasetByRepo(ctx.Repo.Repository) | |||
if err != nil { | |||
log.Warn("can not get dataset.", err) | |||
ctx.JSON(200, map[string]interface{}{ | |||
"code": 0, | |||
"message": "", | |||
"data": []*api.Dataset{}, | |||
}) | |||
return | |||
} | |||
dataset.Repo = ctx.Repo.Repository | |||
ctx.JSON(200, map[string]interface{}{ | |||
"code": 0, | |||
"message": "", | |||
"data": []*api.Dataset{convert.ToDataset(dataset)}, | |||
}) | |||
} | |||
func MyDatasetsMultiple(ctx *context.APIContext) { | |||
opts := &models.SearchDatasetOptions{ | |||
@@ -42,6 +42,7 @@ const ( | |||
tplExploreImages base.TplName = "explore/images" | |||
tplExploreExploreDataAnalysis base.TplName = "explore/data_analysis" | |||
tplHomeTerm base.TplName = "terms" | |||
tplHomeAnnual base.TplName = "annual_privacy" | |||
tplHomePrivacy base.TplName = "privacy" | |||
tplResoruceDesc base.TplName = "resource_desc" | |||
tplRepoSquare base.TplName = "explore/repos/square" | |||
@@ -966,6 +967,9 @@ func RecommendHomeInfo(ctx *context.Context) { | |||
func HomeTerm(ctx *context.Context) { | |||
ctx.HTML(200, tplHomeTerm) | |||
} | |||
func HomeAnnual(ctx *context.Context) { | |||
ctx.HTML(200, tplHomeAnnual) | |||
} | |||
func HomePrivacy(ctx *context.Context) { | |||
ctx.HTML(200, tplHomePrivacy) | |||
@@ -287,7 +287,7 @@ func cloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { | |||
} | |||
var datasetInfos map[string]models.DatasetInfo | |||
var datasetNames string | |||
var attachSize int | |||
var attachSize int64 | |||
if uuids != "" { | |||
datasetInfos, datasetNames, err = models.GetDatasetInfo(uuids) | |||
if err != nil { | |||
@@ -301,10 +301,10 @@ func cloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { | |||
for _, infos := range datasetInfos { | |||
attachSize += infos.Size | |||
} | |||
if attachSize > int(setting.DebugAttachSize*1000*1000*1000) { | |||
log.Error("The DatasetSize exceeds the limit (%d)", int(setting.DebugAttachSize)) // GB | |||
if attachSize > int64(setting.DebugAttachSize*1000*1000*1000) { | |||
log.Error("The DatasetSize exceeds the limit (%dGB)", setting.DebugAttachSize) // GB | |||
cloudBrainNewDataPrepare(ctx, jobType) | |||
ctx.RenderWithErr(ctx.Tr("cloudbrain.error.debug_datasetsize", int(setting.DebugAttachSize*1000*1000*1000)), tpl, &form) | |||
ctx.RenderWithErr(ctx.Tr("cloudbrain.error.debug_datasetsize", setting.DebugAttachSize), tpl, &form) | |||
return | |||
} | |||
} | |||
@@ -609,8 +609,10 @@ func CloudBrainInferenceJobCreate(ctx *context.Context, form auth.CreateCloudBra | |||
} | |||
/** | |||
检查用户传输的参数是否符合专属资源池 | |||
/* | |||
* | |||
检查用户传输的参数是否符合专属资源池 | |||
*/ | |||
func checkCloudBrainSpecialPool(ctx *context.Context, jobType string, queue string, resourceSpecId int) string { | |||
if cloudbrain.SpecialPools != nil { | |||
@@ -1343,8 +1345,8 @@ func DeleteJobsByRepoID(repoID int64) { | |||
DeleteJobs(cloudBrains) | |||
} | |||
/** | |||
/* | |||
* | |||
*/ | |||
func StopJobs(cloudBrains []*models.Cloudbrain) { | |||
@@ -1374,14 +1376,11 @@ func StopJobs(cloudBrains []*models.Cloudbrain) { | |||
logErrorAndUpdateJobStatus(err, taskInfo) | |||
} | |||
} else if taskInfo.Type == models.TypeC2Net { | |||
if taskInfo.JobType == string(models.JobTypeTrain) { | |||
err := retry(3, time.Second*30, func() error { | |||
_, err := grampus.StopJob(taskInfo.JobID) | |||
return err | |||
}) | |||
logErrorAndUpdateJobStatus(err, taskInfo) | |||
} | |||
err := retry(3, time.Second*30, func() error { | |||
_, err := grampus.StopJob(taskInfo.JobID, taskInfo.JobType) | |||
return err | |||
}) | |||
logErrorAndUpdateJobStatus(err, taskInfo) | |||
} | |||
} | |||
} | |||
@@ -205,6 +205,7 @@ func GrampusNotebookCreate(ctx *context.Context, form auth.CreateGrampusNotebook | |||
var datasetInfos map[string]models.DatasetInfo | |||
var datasetNames string | |||
var attachSize int64 | |||
//var | |||
if uuid != "" { | |||
datasetInfos, datasetNames, err = models.GetDatasetInfo(uuid, computeSourceSimple) | |||
@@ -220,6 +221,15 @@ func GrampusNotebookCreate(ctx *context.Context, form auth.CreateGrampusNotebook | |||
ctx.RenderWithErr(ctx.Tr("cloudbrain.error.partial_datasets_not_available"), tpl, &form) | |||
return | |||
} | |||
for _, infos := range datasetInfos { | |||
attachSize += infos.Size | |||
} | |||
if attachSize > int64(setting.DebugAttachSize*1000*1000*1000) { | |||
log.Error("The DatasetSize exceeds the limit (%dGB)", setting.DebugAttachSize) // GB | |||
grampusNotebookNewDataPrepare(ctx, processType) | |||
ctx.RenderWithErr(ctx.Tr("cloudbrain.error.debug_datasetsize", setting.DebugAttachSize), tpl, &form) | |||
return | |||
} | |||
} | |||
//prepare code and out path | |||
@@ -1388,9 +1398,9 @@ func GrampusGetLog(ctx *context.Context) { | |||
return | |||
} | |||
content, err := grampus.GetTrainJobLog(job.JobID) | |||
result, err := grampus.GetJob(jobID) | |||
if err != nil { | |||
log.Error("GetTrainJobLog failed: %v", err, ctx.Data["MsgID"]) | |||
log.Error("GetJob(%s) failed:%v", job.JobName, err) | |||
ctx.JSON(http.StatusOK, map[string]interface{}{ | |||
"JobName": job.JobName, | |||
"Content": "", | |||
@@ -1398,20 +1408,26 @@ func GrampusGetLog(ctx *context.Context) { | |||
}) | |||
return | |||
} | |||
result, err := grampus.GetJob(jobID) | |||
exitDiagnostics := "" | |||
if result != nil { | |||
exitDiagnostics = result.ExitDiagnostics | |||
} | |||
content, err := grampus.GetTrainJobLog(job.JobID) | |||
if err != nil { | |||
log.Error("GetJob(%s) failed:%v", job.JobName, err) | |||
log.Error("GetTrainJobLog failed: %v", err, ctx.Data["MsgID"]) | |||
ctx.JSON(http.StatusOK, map[string]interface{}{ | |||
"JobName": job.JobName, | |||
"Content": content, | |||
"Content": exitDiagnostics, | |||
"CanLogDownload": false, | |||
}) | |||
return | |||
} | |||
if result != nil { | |||
job.Status = grampus.TransTrainJobStatus(result.JobInfo.Status) | |||
if job.Status == models.GrampusStatusFailed { | |||
content = content + "\n" + result.ExitDiagnostics | |||
content = content + "\n" + exitDiagnostics | |||
} | |||
} | |||
@@ -223,16 +223,16 @@ func Notebook2Create(ctx *context.Context, form auth.CreateModelArtsNotebookForm | |||
} | |||
var datasetInfos map[string]models.DatasetInfo | |||
var attachSize int | |||
var attachSize int64 | |||
if uuid != "" { | |||
datasetInfos, _, err = models.GetDatasetInfo(uuid) | |||
for _, infos := range datasetInfos { | |||
attachSize += infos.Size | |||
} | |||
if attachSize > int(setting.DebugAttachSize*1000*1000*1000) { | |||
log.Error("The DatasetSize exceeds the limit (%d)", int(setting.DebugAttachSize)) //GB | |||
if attachSize > int64(setting.DebugAttachSize*1000*1000*1000) { | |||
log.Error("The DatasetSize exceeds the limit (%dGB)", setting.DebugAttachSize) //GB | |||
notebookNewDataPrepare(ctx) | |||
ctx.RenderWithErr(ctx.Tr("cloudbrain.error.debug_datasetsize", int(setting.DebugAttachSize*1000*1000*1000)), tplModelArtsNotebookNew, &form) | |||
ctx.RenderWithErr(ctx.Tr("cloudbrain.error.debug_datasetsize", setting.DebugAttachSize), tplModelArtsNotebookNew, &form) | |||
return | |||
} | |||
} | |||
@@ -460,7 +460,7 @@ func NotebookDebug2(ctx *context.Context) { | |||
} | |||
if ctx.QueryTrim("file") != "" { | |||
ctx.Redirect(getFileUrl(result.Url, ctx.QueryTrim("file")) + "?token=" + result.Token) | |||
ctx.Redirect(getFileUrl(result.Url, ctx.QueryTrim("file")) + "&token=" + result.Token) | |||
} else { | |||
if task.BootFile != "" { | |||
go cloudbrainTask.UploadNotebookFiles(task) | |||
@@ -359,6 +359,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
m.Get("/all/dosearch/", routers.SearchApi) | |||
m.Post("/user/login/kanban", user.SignInPostAPI) | |||
m.Get("/home/term", routers.HomeTerm) | |||
m.Get("/home/annual_privacy", routers.HomeAnnual) | |||
m.Get("/home/notice", routers.HomeNoticeTmpl) | |||
m.Get("/home/privacy", routers.HomePrivacy) | |||
m.Get("/extension/tuomin/upload", modelapp.ProcessImageUI) | |||
@@ -1189,7 +1190,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
m.Get("/download_multi_model", cloudbrain.AdminOrJobCreaterRight, repo.CloudBrainDownloadMultiModel) | |||
}) | |||
m.Get("/create", reqWechatBind, reqRepoCloudBrainWriter, context.PointAccount(), repo.CloudBrainNew) | |||
m.Post("/create", reqWechatBind, reqRepoCloudBrainWriter, bindIgnErr(auth.CreateCloudBrainForm{}), repo.CloudBrainCreate) | |||
m.Post("/create", reqWechatBind, reqRepoCloudBrainWriter, bindIgnErr(auth.CreateCloudBrainForm{}), context.PointAccount(), repo.CloudBrainCreate) | |||
m.Group("/benchmark", func() { | |||
m.Get("", reqRepoCloudBrainReader, repo.CloudBrainBenchmarkIndex) | |||
@@ -1200,7 +1201,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
m.Get("/rate", reqRepoCloudBrainReader, repo.GetRate) | |||
}) | |||
m.Get("/create", reqWechatBind, reqRepoCloudBrainWriter, context.PointAccount(), repo.CloudBrainBenchmarkNew) | |||
m.Post("/create", reqWechatBind, reqRepoCloudBrainWriter, bindIgnErr(auth.CreateCloudBrainForm{}), repo.CloudBrainBenchmarkCreate) | |||
m.Post("/create", reqWechatBind, reqRepoCloudBrainWriter, bindIgnErr(auth.CreateCloudBrainForm{}), context.PointAccount(), repo.CloudBrainBenchmarkCreate) | |||
m.Get("/get_child_types", repo.GetChildTypes) | |||
}) | |||
@@ -1217,7 +1218,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
m.Post("/create_version", reqWechatBind, cloudbrain.AdminOrJobCreaterRightForTrain, bindIgnErr(auth.CreateCloudBrainForm{}), repo.CloudBrainTrainJobVersionCreate) | |||
}) | |||
m.Get("/create", reqWechatBind, reqRepoCloudBrainWriter, context.PointAccount(), repo.CloudBrainTrainJobNew) | |||
m.Post("/create", reqWechatBind, reqRepoCloudBrainWriter, bindIgnErr(auth.CreateCloudBrainForm{}), repo.CloudBrainCreate) | |||
m.Post("/create", reqWechatBind, reqRepoCloudBrainWriter, bindIgnErr(auth.CreateCloudBrainForm{}), context.PointAccount(), repo.CloudBrainCreate) | |||
}) | |||
m.Group("/inference-job", func() { | |||
m.Group("/:jobid", func() { | |||
@@ -1227,7 +1228,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
m.Get("/downloadall", cloudbrain.AdminOrJobCreaterRightForTrain, repo.DownloadGPUInferenceResultFile) | |||
}) | |||
m.Get("/create", reqWechatBind, reqRepoCloudBrainWriter, context.PointAccount(), repo.InferenceCloudBrainJobNew) | |||
m.Post("/create", reqWechatBind, reqRepoCloudBrainWriter, bindIgnErr(auth.CreateCloudBrainInferencForm{}), repo.CloudBrainInferenceJobCreate) | |||
m.Post("/create", reqWechatBind, reqRepoCloudBrainWriter, bindIgnErr(auth.CreateCloudBrainInferencForm{}), context.PointAccount(), repo.CloudBrainInferenceJobCreate) | |||
}) | |||
}, context.RepoRef()) | |||
m.Group("/grampus", func() { | |||
@@ -1241,7 +1242,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
}) | |||
m.Get("/create", reqWechatBind, reqRepoCloudBrainWriter, context.PointAccount(), repo.GrampusNotebookNew) | |||
m.Post("/create", reqWechatBind, reqRepoCloudBrainWriter, bindIgnErr(auth.CreateGrampusNotebookForm{}), repo.GrampusNotebookCreate) | |||
m.Post("/create", reqWechatBind, reqRepoCloudBrainWriter, bindIgnErr(auth.CreateGrampusNotebookForm{}), context.PointAccount(), repo.GrampusNotebookCreate) | |||
}) | |||
m.Group("/train-job", func() { | |||
@@ -1256,11 +1257,11 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
}) | |||
m.Group("/gpu", func() { | |||
m.Get("/create", reqWechatBind, reqRepoCloudBrainWriter, context.PointAccount(), repo.GrampusTrainJobGPUNew) | |||
m.Post("/create", reqWechatBind, reqRepoCloudBrainWriter, bindIgnErr(auth.CreateGrampusTrainJobForm{}), repo.GrampusTrainJobGpuCreate) | |||
m.Post("/create", reqWechatBind, reqRepoCloudBrainWriter, bindIgnErr(auth.CreateGrampusTrainJobForm{}), context.PointAccount(), repo.GrampusTrainJobGpuCreate) | |||
}) | |||
m.Group("/npu", func() { | |||
m.Get("/create", reqWechatBind, reqRepoCloudBrainWriter, context.PointAccount(), repo.GrampusTrainJobNPUNew) | |||
m.Post("/create", reqWechatBind, reqRepoCloudBrainWriter, bindIgnErr(auth.CreateGrampusTrainJobForm{}), repo.GrampusTrainJobNpuCreate) | |||
m.Post("/create", reqWechatBind, reqRepoCloudBrainWriter, bindIgnErr(auth.CreateGrampusTrainJobForm{}), context.PointAccount(), repo.GrampusTrainJobNpuCreate) | |||
}) | |||
}) | |||
}, context.RepoRef()) | |||
@@ -1309,7 +1310,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
}) | |||
m.Get("/create_gpu", reqWechatBind, reqRepoCloudBrainWriter, context.PointAccount(), repo.AiSafetyCreateForGetGPU) | |||
m.Get("/create_npu", reqWechatBind, reqRepoCloudBrainWriter, context.PointAccount(), repo.AiSafetyCreateForGetNPU) | |||
m.Post("/create", reqWechatBind, reqRepoCloudBrainWriter, repo.AiSafetyCreateForPost) | |||
m.Post("/create", reqWechatBind, reqRepoCloudBrainWriter, context.PointAccount(), repo.AiSafetyCreateForPost) | |||
}, context.RepoRef()) | |||
m.Group("/debugjob", func() { | |||
@@ -1326,7 +1327,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
m.Post("/del", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.NotebookDel) | |||
}) | |||
m.Get("/create", reqWechatBind, reqRepoCloudBrainWriter, context.PointAccount(), repo.NotebookNew) | |||
m.Post("/create", reqWechatBind, reqRepoCloudBrainWriter, bindIgnErr(auth.CreateModelArtsNotebookForm{}), repo.Notebook2Create) | |||
m.Post("/create", reqWechatBind, reqRepoCloudBrainWriter, bindIgnErr(auth.CreateModelArtsNotebookForm{}), context.PointAccount(), repo.Notebook2Create) | |||
}) | |||
m.Group("/train-job", func() { | |||
@@ -1339,10 +1340,10 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
m.Get("/download_multi_model", cloudbrain.AdminOrJobCreaterRightForTrain, repo.MultiModelDownload) | |||
m.Get("/download_log_file", cloudbrain.AdminOrJobCreaterRightForTrain, repo.TrainJobDownloadLogFile) | |||
m.Get("/create_version", reqWechatBind, cloudbrain.AdminOrJobCreaterRightForTrain, context.PointAccount(), repo.TrainJobNewVersion) | |||
m.Post("/create_version", reqWechatBind, cloudbrain.AdminOrJobCreaterRightForTrain, bindIgnErr(auth.CreateModelArtsTrainJobForm{}), repo.TrainJobCreateVersion) | |||
m.Post("/create_version", reqWechatBind, cloudbrain.AdminOrJobCreaterRightForTrain, bindIgnErr(auth.CreateModelArtsTrainJobForm{}), context.PointAccount(), repo.TrainJobCreateVersion) | |||
}) | |||
m.Get("/create", reqWechatBind, reqRepoCloudBrainWriter, context.PointAccount(), repo.TrainJobNew) | |||
m.Post("/create", reqWechatBind, reqRepoCloudBrainWriter, bindIgnErr(auth.CreateModelArtsTrainJobForm{}), repo.TrainJobCreate) | |||
m.Post("/create", reqWechatBind, reqRepoCloudBrainWriter, bindIgnErr(auth.CreateModelArtsTrainJobForm{}), context.PointAccount(), repo.TrainJobCreate) | |||
m.Get("/para-config-list", reqRepoCloudBrainReader, repo.TrainJobGetConfigList) | |||
}) | |||
@@ -1355,7 +1356,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
m.Get("/downloadall", cloudbrain.AdminOrJobCreaterRightForTrain, repo.DownloadMultiResultFile) | |||
}) | |||
m.Get("/create", reqWechatBind, reqRepoCloudBrainWriter, context.PointAccount(), repo.InferenceJobNew) | |||
m.Post("/create", reqWechatBind, reqRepoCloudBrainWriter, bindIgnErr(auth.CreateModelArtsInferenceJobForm{}), repo.InferenceJobCreate) | |||
m.Post("/create", reqWechatBind, reqRepoCloudBrainWriter, bindIgnErr(auth.CreateModelArtsInferenceJobForm{}), context.PointAccount(), repo.InferenceJobCreate) | |||
}) | |||
}, context.RepoRef()) | |||
@@ -276,7 +276,6 @@ func SignInPostAPI(ctx *context.Context) { | |||
func SignInPostCommon(ctx *context.Context, form auth.SignInForm) { | |||
ctx.Data["Title"] = ctx.Tr("sign_in") | |||
orderedOAuth2Names, oauth2Providers, err := models.GetActiveOAuth2Providers() | |||
if err != nil { | |||
ctx.ServerError("UserSignIn", err) | |||
@@ -291,7 +290,6 @@ func SignInPostCommon(ctx *context.Context, form auth.SignInForm) { | |||
ctx.Data["IsCourse"] = ctx.QueryBool("course") | |||
ctx.Data["EnableSSPI"] = models.IsSSPIEnabled() | |||
ctx.Data["EnableCloudBrain"] = true | |||
if ctx.HasError() { | |||
ctx.HTML(200, tplSignIn) | |||
return | |||
@@ -765,7 +763,6 @@ func handleSignInFull(ctx *context.Context, u *models.User, remember bool, obeyR | |||
} | |||
return redirectTo | |||
} | |||
if obeyRedirect { | |||
ctx.Redirect(setting.AppSubURL + "/dashboard") | |||
} | |||
@@ -0,0 +1,35 @@ | |||
{{template "base/head_home" .}} | |||
<div class="ui container"> | |||
<h1 class="ui center am-pt-30 am-pb-20">OpenI启智社区2022年度报告授权协议</h1> | |||
<div class="ui divider am-pb-10"></div> | |||
<p> | |||
感谢您阅读《OpenI启智社区2022年度报告授权协议》!在您正式使用OpenI启智社区2022年度报告之前应仔细阅读并充分理解本协议中的全部内容,如您不同意本协议中的任何条款,请立即停止使用OpenI启智社区2022年度报告。您使用OpenI启智社区2022年度报告的行为将被视为已经仔细阅读、充分理解并毫无保留地接受本协议所有条款。 | |||
</p> | |||
<p> | |||
<strong>1. 制作年度报告</strong> | |||
</p> | |||
<p> | |||
OpenI启智社区2022年度报告将根据您在平台的历史信息,帮助您生成一份专属年度报告。为此,我们将使用2022自然年度您在OpenI启智社区产生的行为信息,包括但不限于用户名、注册时间、创建项目数、项目下载次数、commit次数、代码行数、创建数据集、上传数据集文件、数据集被收藏数、数据集下载数、云脑任务所有相关数据( GPU/NPU 调试任务、训练任务、运行卡时)。您理解并同意,上述信息是OpenI启智社区生成年度报告的必备信息,如您拒绝授权使用,OpenI启智社区将无法为您制作并提供专属年度报告。未经您的书面同意,我们保证不以超越本协议约定范围使用您的个人信息。 | |||
</p> | |||
<p> | |||
<strong>2. 使用年度报告</strong> | |||
</p> | |||
<p> | |||
OpenI启智社区提供的年度报告仅限您个人使用,您可自行留存欣赏或无偿分享、公开。您理解并同意,如因您分享、公开年度报告而产生的任何损失(包括但不限于个人信息泄露等)应由您自行承担,请您在分享、公开年度报告前审慎考虑。 | |||
</p> | |||
<p> | |||
<strong>3. 知识产权</strong> | |||
</p> | |||
<p> | |||
年度报告及其内容(包括但不限于软件、技术、程序、网页、文字、图片、音频、视频、页面设计、商标等)的知识产权由OpenI启智社区享有,您理解并同意,您不得超越本协议目的使用年度报告中的内容素材,如您希望以任何形式将年度报告中的内容素材用于本协议约定范围之外,应当经过所有实际权利人的书面许可。 | |||
</p> | |||
<p> | |||
<strong>4. 隐私政策</strong> | |||
</p> | |||
<p> | |||
其他本隐私保护指引未有涉及的,将适用<a target="_blank" href="/home/term/">《OpenI启智社区AI协作平台使用协议》</a>和<a target="_blank" href="/home/privacy/">《OpenI启智社区AI协作平台隐私协议》</a>。 | |||
</p> | |||
</div> | |||
{{template "base/footer" .}} |
@@ -3,7 +3,7 @@ | |||
<div class="repository"> | |||
{{template "repo/header" .}} | |||
<div class="ui container"> | |||
<div class="cloudbrain-type" style="display: none;" data-cloudbrain-type="{{.datasetType}}" data-repo-link="{{.RepoLink}}" data-flag-model="true"></div> | |||
<div class="cloudbrain-type" style="display: none;" data-cloudbrain-type="{{.datasetType}}" data-repo-link="{{.RepoLink}}" data-flag-model="true" data-dataset-uuid="{{.attachment}}" data-dataset-name="{{.dataset_name}}" data-exceed-size="{{DebugAttachSize}}"></div> | |||
{{if eq .NotStopTaskCount 0}} | |||
{{template "base/alert" .}} | |||
{{end}} | |||
@@ -207,8 +207,8 @@ const en = { | |||
npuEnv: "NPU environment", | |||
newTask: "Create new task", | |||
noQuene: "The current resources are sufficient and no tasks are queued", | |||
queneTips1: "There are currently", | |||
queneTips2: "tasks queued", | |||
queneTips1: "Your current queue position is", | |||
queneTips2: "", | |||
watiResource: "Waiting for resources to be allocated, please be patient", | |||
debug: "Debug", | |||
stop: "Stop", | |||
@@ -208,8 +208,8 @@ const zh = { | |||
npuEnv: "NPU 环境", | |||
newTask: "新建任务", | |||
noQuene: "当前资源充足,没有任务排队", | |||
queneTips1: "当前有", | |||
queneTips2: "个任务正在排队", | |||
queneTips1: "您当前排队位置是第", | |||
queneTips2: "位", | |||
watiResource: "正在等待分配资源,请耐心等待", | |||
debug: "调试", | |||
stop: "停止", | |||
@@ -108,7 +108,7 @@ | |||
<div v-if="btnStatus[0]===0"> | |||
<button class="ui green small button" @click="createTask(0)"></i>{{$t('notebook.newTask')}}</button> | |||
<span v-if="notebookInfo.waitCountGpu==0" class="text">{{$t('notebook.noQuene')}}</span> | |||
<span v-else class="text">{{$t('notebook.queneTips1')}} <span style="color: red;">{{notebookInfo.waitCountGpu}}</span> {{$t('notebook.queneTips2')}}</span> | |||
<span v-else class="text">{{$t('notebook.queneTips1')}} <span style="color: red;">{{notebookInfo.waitCountGpu + 1}}</span> {{$t('notebook.queneTips2')}}</span> | |||
</div> | |||
<div v-else-if="btnStatus[0]===1"> | |||
<button class="ui disabled small button" style="background-color: #888;"><i class="loading spinner icon" style="color: #fff;"></i>{{$t('notebook.newTask')}}</button> | |||
@@ -131,7 +131,7 @@ | |||
<div v-if="btnStatus[2]===0"> | |||
<button class="ui green small button" @click="createTask(2)"></i>{{$t('notebook.newTask')}}</button> | |||
<span v-if="notebookInfo.waitCountNpu==0" class="text">{{$t('notebook.noQuene')}}</span> | |||
<span v-else class="text">{{$t('notebook.queneTips1')}} <span style="color: red;">{{notebookInfo.waitCountNpu}}</span> {{$t('notebook.queneTips2')}}</span> | |||
<span v-else class="text">{{$t('notebook.queneTips1')}} <span style="color: red;">{{notebookInfo.waitCountNpu + 1}}</span> {{$t('notebook.queneTips2')}}</span> | |||
</div> | |||
<div v-else-if="btnStatus[2]===1"> | |||
<button class="ui disabled small button" style="background-color: #888;"><i class="loading spinner icon" style="color: #fff;"></i>{{$t('notebook.newTask')}}</button> | |||
@@ -153,7 +153,7 @@ | |||
<div v-if="btnStatus[1]===0"> | |||
<button class="ui green small button" @click="createTask(1)"></i>{{$t('notebook.newTask')}}</button> | |||
<span v-if="notebookInfo.waitCountGpu==0" class="text">{{$t('notebook.noQuene')}}</span> | |||
<span v-else class="text">{{$t('notebook.queneTips1')}} <span style="color: red;">{{notebookInfo.waitCountGpu}}</span> {{$t('notebook.queneTips2')}}</span> | |||
<span v-else class="text">{{$t('notebook.queneTips1')}} <span style="color: red;">{{notebookInfo.waitCountGpu + 1}}</span> {{$t('notebook.queneTips2')}}</span> | |||
</div> | |||
<div v-else-if="btnStatus[1]===1"> | |||
<button class="ui disabled small button" style="background-color: #888;"><i class="loading spinner icon" style="color: #fff;"></i>{{$t('notebook.newTask')}}</button> | |||