| @@ -2,7 +2,7 @@ | |||
| <h1><img src="public/img/favicon.png" alt="logo" width="30" height="30">AiForge - 启智AI开发协作平台</h1> | |||
| [](https://git.openi.org.cn/OpenI/aiforge/releases/latest) | |||
| [](https://git.openi.org.cn/OpenI/aiforge/releases/latest) | |||
| [](https://opensource.org/licenses/MIT) | |||
| @@ -379,7 +379,7 @@ func GetUnDecompressAttachments() ([]*Attachment, error) { | |||
| func getUnDecompressAttachments(e Engine) ([]*Attachment, error) { | |||
| attachments := make([]*Attachment, 0, 10) | |||
| return attachments, e.Where("decompress_state = ? and dataset_id != 0 and attachment.type = ? and (name like '%.zip' or name like '%.tar.gz' or name like '%.tgz')", DecompressStateInit, TypeCloudBrainOne).Find(&attachments) | |||
| return attachments, e.Where("decompress_state = ? and dataset_id != 0 and (name like '%.zip' or name like '%.tar.gz' or name like '%.tgz')", DecompressStateInit).Find(&attachments) | |||
| } | |||
| func GetAllPublicAttachments() ([]*AttachmentUsername, error) { | |||
| @@ -429,7 +429,7 @@ func GetAllUserAttachments(userID int64) ([]*AttachmentUsername, error) { | |||
| func getModelArtsUserAttachments(e Engine, userID int64) ([]*AttachmentUsername, error) { | |||
| attachments := make([]*AttachmentUsername, 0, 10) | |||
| if err := e.Table("attachment").Join("LEFT", "`user`", "attachment.uploader_id "+ | |||
| "= `user`.id").Where("attachment.type = ? and (uploader_id= ? or is_private = ?)", TypeCloudBrainNotebook, userID, false).Find(&attachments); err != nil { | |||
| "= `user`.id").Where("attachment.type = ? and (uploader_id= ? or is_private = ?)", TypeCloudBrainTwo, userID, false).Find(&attachments); err != nil { | |||
| return nil, err | |||
| } | |||
| return attachments, nil | |||
| @@ -29,6 +29,7 @@ const ( | |||
| JobTypeBenchmark JobType = "BENCHMARK" | |||
| JobTypeSnn4imagenet JobType = "SNN4IMAGENET" | |||
| JobTypeBrainScore JobType = "BRAINSCORE" | |||
| JobTypeTrain JobType = "TRAIN" | |||
| ModelArtsCreateQueue ModelArtsJobStatus = "CREATE_QUEUING" //免费资源创建排队中 | |||
| ModelArtsCreating ModelArtsJobStatus = "CREATING" //创建中 | |||
| @@ -70,6 +71,7 @@ type Cloudbrain struct { | |||
| VersionID int64 `xorm:"INDEX DEFAULT 0"` | |||
| VersionName string | |||
| Uuid string | |||
| DatasetName string | |||
| User *User `xorm:"-"` | |||
| Repo *Repository `xorm:"-"` | |||
| @@ -152,7 +154,8 @@ type CloudbrainsOptions struct { | |||
| SortType string | |||
| CloudbrainIDs []int64 | |||
| // JobStatus CloudbrainStatus | |||
| Type int | |||
| Type int | |||
| JobType string | |||
| } | |||
| type TaskPod struct { | |||
| TaskRoleStatus struct { | |||
| @@ -845,6 +848,12 @@ func Cloudbrains(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, error) { | |||
| ) | |||
| } | |||
| if (opts.JobType) != "" { | |||
| cond = cond.And( | |||
| builder.Eq{"cloudbrain.job_type": opts.JobType}, | |||
| ) | |||
| } | |||
| // switch opts.JobStatus { | |||
| // case JobWaiting: | |||
| // cond.And(builder.Eq{"cloudbrain.status": int(JobWaiting)}) | |||
| @@ -14,11 +14,8 @@ const ( | |||
| ) | |||
| const ( | |||
| TypeCloudBrainOne = 0 | |||
| TypeCloudBrainNotebook = 1 | |||
| TypeCloudBrainTrainJob = 2 | |||
| TypeCloudBrainTwo = 1 | |||
| TypeCloudBrainOne int = iota | |||
| TypeCloudBrainTwo | |||
| ) | |||
| type FileChunk struct { | |||
| @@ -1356,6 +1356,15 @@ func GetIssueStats(opts *IssueStatsOptions) (*IssueStats, error) { | |||
| return accum, nil | |||
| } | |||
| func GetPullCountByUserAndRepoId(repoId int64, userId int64) int64 { | |||
| issue := new(Issue) | |||
| total, err := x.Where("is_pull=true and repo_id=? and poster_id=?", repoId, userId).Count(issue) | |||
| if err != nil { | |||
| return 0 | |||
| } | |||
| return total | |||
| } | |||
| func getIssueStatsChunk(opts *IssueStatsOptions, issueIDs []int64) (*IssueStats, error) { | |||
| stats := &IssueStats{} | |||
| @@ -2,12 +2,18 @@ package models | |||
| import ( | |||
| "fmt" | |||
| "sort" | |||
| "strings" | |||
| "time" | |||
| "code.gitea.io/gitea/modules/git" | |||
| ) | |||
| type ContributorWithUserId struct { | |||
| git.Contributor | |||
| UserId int64 | |||
| } | |||
| func GetRepoKPIStats(repo *Repository) (*git.RepoKPIStats, error) { | |||
| wikiPath := "" | |||
| if repo.HasWiki() { | |||
| @@ -63,22 +69,39 @@ func getRepoKPIStats(repoPath string, wikiPath string) (*git.RepoKPIStats, error | |||
| } | |||
| if recentlyContributors != nil { | |||
| resentlyContributorDistinctDict := make(map[string]int, 0) | |||
| for _, recentlyContributor := range recentlyContributors { | |||
| user, err := GetUserByActivateEmail(recentlyContributor.Email) | |||
| var ok bool | |||
| if err == nil { | |||
| _, ok = contributorDistinctDict[user.Email] | |||
| value, ok := resentlyContributorDistinctDict[user.Email] | |||
| if !ok { | |||
| resentlyContributorDistinctDict[user.Email] = recentlyContributor.CommitCnt | |||
| } else { | |||
| resentlyContributorDistinctDict[user.Email] = value + recentlyContributor.CommitCnt | |||
| } | |||
| } else { | |||
| _, ok = contributorDistinctDict[recentlyContributor.Email] | |||
| value, ok := resentlyContributorDistinctDict[recentlyContributor.Email] | |||
| if !ok { | |||
| resentlyContributorDistinctDict[recentlyContributor.Email] = recentlyContributor.CommitCnt | |||
| } else { | |||
| resentlyContributorDistinctDict[recentlyContributor.Email] = value + recentlyContributor.CommitCnt | |||
| } | |||
| } | |||
| if !ok { | |||
| } | |||
| for k, v := range resentlyContributorDistinctDict { | |||
| count, ok := contributorDistinctDict[k] | |||
| if ok && count == v { | |||
| stats.ContributorsAdded++ | |||
| newContributersDict[recentlyContributor.Email] = struct{}{} | |||
| } | |||
| } | |||
| } | |||
| stats.Contributors = int64(len(contributorDistinctDict)) | |||
| @@ -101,6 +124,64 @@ func getRepoKPIStats(repoPath string, wikiPath string) (*git.RepoKPIStats, error | |||
| } | |||
| func GetTop10Contributor(repoPath string) ([]ContributorWithUserId, error) { | |||
| contributors, err := git.GetContributors(repoPath) | |||
| if err != nil { | |||
| return make([]ContributorWithUserId, 0), err | |||
| } | |||
| contributorDistinctDict := make(map[string]ContributorWithUserId, 0) | |||
| if contributors != nil { | |||
| for _, contributor := range contributors { | |||
| if strings.Compare(contributor.Email, "") == 0 { | |||
| continue | |||
| } | |||
| user, err := GetUserByActivateEmail(contributor.Email) | |||
| if err == nil { | |||
| value, ok := contributorDistinctDict[user.Email] | |||
| if !ok { | |||
| contributorDistinctDict[user.Email] = ContributorWithUserId{ | |||
| contributor, | |||
| user.ID, | |||
| } | |||
| } else { | |||
| value.CommitCnt += contributor.CommitCnt | |||
| } | |||
| } else { | |||
| value, ok := contributorDistinctDict[contributor.Email] | |||
| if !ok { | |||
| contributorDistinctDict[contributor.Email] = ContributorWithUserId{ | |||
| contributor, | |||
| -1, | |||
| } | |||
| } else { | |||
| value.CommitCnt += contributor.CommitCnt | |||
| } | |||
| } | |||
| } | |||
| v := make([]ContributorWithUserId, 0, len(contributorDistinctDict)) | |||
| for _, value := range contributorDistinctDict { | |||
| v = append(v, value) | |||
| } | |||
| sort.Slice(v, func(i, j int) bool { | |||
| return v[i].CommitCnt > v[j].CommitCnt | |||
| }) | |||
| if len(v) <= 10 { | |||
| return v, nil | |||
| } else { | |||
| return v[0:10], nil | |||
| } | |||
| } | |||
| return make([]ContributorWithUserId, 0), nil | |||
| } | |||
| func setKeyContributerDict(contributorDistinctDict map[string]int, email string, keyContributorsDict map[string]struct{}) { | |||
| if contributorDistinctDict[email] >= 3 { | |||
| _, ok := keyContributorsDict[email] | |||
| @@ -114,6 +114,17 @@ func (repo *Repository) isCollaborator(e Engine, userID int64) (bool, error) { | |||
| return e.Get(&Collaboration{RepoID: repo.ID, UserID: userID}) | |||
| } | |||
| func (repo *Repository) GetCollaboratorMode(userID int64) int { | |||
| collaboration := &Collaboration{RepoID: repo.ID, UserID: userID} | |||
| has, err := x.Get(&collaboration) | |||
| if err != nil || !has { | |||
| return -1 | |||
| } else { | |||
| return int(collaboration.Mode) | |||
| } | |||
| } | |||
| // IsCollaborator check if a user is a collaborator of a repository | |||
| func (repo *Repository) IsCollaborator(userID int64) (bool, error) { | |||
| return repo.isCollaborator(x, userID) | |||
| @@ -9,56 +9,56 @@ import ( | |||
| // RepoStatistic statistic info of all repository | |||
| type RepoStatistic struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| RepoID int64 `xorm:"unique(s) NOT NULL"` | |||
| Name string `xorm:"INDEX"` | |||
| IsPrivate bool | |||
| Date string `xorm:"unique(s) NOT NULL"` | |||
| NumWatches int64 `xorm:"NOT NULL DEFAULT 0"` | |||
| NumWatchesAdded int64 `xorm:"NOT NULL DEFAULT 0"` | |||
| NumStars int64 `xorm:"NOT NULL DEFAULT 0"` | |||
| NumStarsAdded int64 `xorm:"NOT NULL DEFAULT 0"` | |||
| NumForks int64 `xorm:"NOT NULL DEFAULT 0"` | |||
| NumForksAdded int64 `xorm:"NOT NULL DEFAULT 0"` | |||
| NumDownloads int64 `xorm:"NOT NULL DEFAULT 0"` | |||
| NumDownloadsAdded int64 `xorm:"NOT NULL DEFAULT 0"` | |||
| NumComments int64 `xorm:"NOT NULL DEFAULT 0"` | |||
| NumCommentsAdded int64 `xorm:"NOT NULL DEFAULT 0"` | |||
| NumVisits int64 `xorm:"NOT NULL DEFAULT 0"` | |||
| NumClosedIssues int64 `xorm:"NOT NULL DEFAULT 0"` | |||
| NumClosedIssuesAdded int64 `xorm:"NOT NULL DEFAULT 0"` | |||
| NumVersions int64 `xorm:"NOT NULL DEFAULT 0"` | |||
| NumDevMonths int64 `xorm:"NOT NULL DEFAULT 0"` | |||
| RepoSize int64 `xorm:"NOT NULL DEFAULT 0"` | |||
| DatasetSize int64 `xorm:"NOT NULL DEFAULT 0"` | |||
| NumModels int64 `xorm:"NOT NULL DEFAULT 0"` | |||
| NumWikiViews int64 `xorm:"NOT NULL DEFAULT 0"` | |||
| NumCommits int64 `xorm:"NOT NULL DEFAULT 0"` | |||
| NumCommitsAdded int64 `xorm:"NOT NULL DEFAULT 0"` | |||
| NumIssues int64 `xorm:"NOT NULL DEFAULT 0"` | |||
| NumIssuesAdded int64 `xorm:"NOT NULL DEFAULT 0"` | |||
| NumPulls int64 `xorm:"NOT NULL DEFAULT 0"` | |||
| NumPullsAdded int64 `xorm:"NOT NULL DEFAULT 0"` | |||
| IssueFixedRate float32 `xorm:"NOT NULL"` | |||
| NumContributor int64 `xorm:"NOT NULL DEFAULT 0"` | |||
| NumContributorAdded int64 `xorm:"NOT NULL DEFAULT 0"` | |||
| NumKeyContributor int64 `xorm:"NOT NULL DEFAULT 0"` | |||
| NumContributorsGrowth int64 `xorm:"NOT NULL DEFAULT 0"` | |||
| NumCommitsGrowth int64 `xorm:"NOT NULL DEFAULT 0"` | |||
| NumCommitLinesGrowth int64 `xorm:"NOT NULL DEFAULT 0"` | |||
| NumIssuesGrowth int64 `xorm:"NOT NULL DEFAULT 0"` | |||
| NumCommentsGrowth int64 `xorm:"NOT NULL DEFAULT 0"` | |||
| Impact float64 `xorm:"NOT NULL DEFAULT 0"` | |||
| Completeness float64 `xorm:"NOT NULL DEFAULT 0"` | |||
| Liveness float64 `xorm:"NOT NULL DEFAULT 0"` | |||
| ProjectHealth float64 `xorm:"NOT NULL DEFAULT 0"` | |||
| TeamHealth float64 `xorm:"NOT NULL DEFAULT 0"` | |||
| Growth float64 `xorm:"NOT NULL DEFAULT 0"` | |||
| RadarTotal float64 `xorm:"NOT NULL DEFAULT 0"` | |||
| CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` | |||
| UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` | |||
| ID int64 `xorm:"pk autoincr" json:"-"` | |||
| RepoID int64 `xorm:"unique(s) NOT NULL" json:"repo_id"` | |||
| Name string `xorm:"INDEX" json:"name"` | |||
| IsPrivate bool `json:"isPrivate"` | |||
| Date string `xorm:"unique(s) NOT NULL" json:"date"` | |||
| NumWatches int64 `xorm:"NOT NULL DEFAULT 0" json:"watch"` | |||
| NumWatchesAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
| NumStars int64 `xorm:"NOT NULL DEFAULT 0" json:"star"` | |||
| NumStarsAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
| NumForks int64 `xorm:"NOT NULL DEFAULT 0" json:"fork"` | |||
| NumForksAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
| NumDownloads int64 `xorm:"NOT NULL DEFAULT 0" json:"download"` | |||
| NumDownloadsAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
| NumComments int64 `xorm:"NOT NULL DEFAULT 0" json:"comment"` | |||
| NumCommentsAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
| NumVisits int64 `xorm:"NOT NULL DEFAULT 0" json:"view"` | |||
| NumClosedIssues int64 `xorm:"NOT NULL DEFAULT 0" json:"issueClosed"` | |||
| NumClosedIssuesAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
| NumVersions int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
| NumDevMonths int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
| RepoSize int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
| DatasetSize int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
| NumModels int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
| NumWikiViews int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
| NumCommits int64 `xorm:"NOT NULL DEFAULT 0" json:"commit"` | |||
| NumCommitsAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
| NumIssues int64 `xorm:"NOT NULL DEFAULT 0" json:"issue"` | |||
| NumIssuesAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
| NumPulls int64 `xorm:"NOT NULL DEFAULT 0" json:"pr"` | |||
| NumPullsAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
| IssueFixedRate float32 `xorm:"NOT NULL" json:"issueClosedRatio"` | |||
| NumContributor int64 `xorm:"NOT NULL DEFAULT 0" json:"contributor"` | |||
| NumContributorAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
| NumKeyContributor int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
| NumContributorsGrowth int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
| NumCommitsGrowth int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
| NumCommitLinesGrowth int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
| NumIssuesGrowth int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
| NumCommentsGrowth int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
| Impact float64 `xorm:"NOT NULL DEFAULT 0" json:"impact"` | |||
| Completeness float64 `xorm:"NOT NULL DEFAULT 0" json:"completeness"` | |||
| Liveness float64 `xorm:"NOT NULL DEFAULT 0" json:"liveness"` | |||
| ProjectHealth float64 `xorm:"NOT NULL DEFAULT 0" json:"projectHealth"` | |||
| TeamHealth float64 `xorm:"NOT NULL DEFAULT 0" json:"teamHealth"` | |||
| Growth float64 `xorm:"NOT NULL DEFAULT 0" json:"growth"` | |||
| RadarTotal float64 `xorm:"NOT NULL DEFAULT 0" json:"openi"` | |||
| CreatedUnix timeutil.TimeStamp `xorm:"INDEX created" json:"-"` | |||
| UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated" json:"-"` | |||
| } | |||
| func DeleteRepoStatDaily(date string) error { | |||
| @@ -81,9 +81,60 @@ func DeleteRepoStatDaily(date string) error { | |||
| return nil | |||
| } | |||
| func GetRepoStatisticByDate(date string) ([]*RepoStatistic, error) { | |||
| func CountRepoStatByRawSql(sql string) (int64, error) { | |||
| return xStatistic.SQL(sql).Count() | |||
| } | |||
| func GetRepoStatisticByRawSql(sql string) []*RepoStatistic { | |||
| repoStatistics := make([]*RepoStatistic, 0) | |||
| xStatistic.SQL(sql).Find(&repoStatistics) | |||
| return repoStatistics | |||
| } | |||
| func GetRepoStatLastUpdatedTime(repoId ...string) (string, string, error) { | |||
| repoStatistic := new(RepoStatistic) | |||
| var has bool | |||
| var err error | |||
| if len(repoId) == 0 { | |||
| has, err = xStatistic.Desc("created_unix").Limit(1).Cols("created_unix", "date").Get(repoStatistic) | |||
| } else { | |||
| has, err = xStatistic.Where("repo_id=?", repoId[0]).Desc("created_unix").Limit(1).Cols("created_unix", "date").Get(repoStatistic) | |||
| } | |||
| if err != nil { | |||
| return "", "", err | |||
| } else { | |||
| if has { | |||
| return repoStatistic.CreatedUnix.Format("2006-01-02 15:04:05"), repoStatistic.Date, nil | |||
| } else { | |||
| return "", "", fmt.Errorf("Can not get the latest record.") | |||
| } | |||
| } | |||
| } | |||
| func GetRepoStatisticByDateAndRepoId(date string, repoId int64) (*RepoStatistic, error) { | |||
| repoStatistic := new(RepoStatistic) | |||
| has, err := xStatistic.Where("date=? and repo_id=?", date, repoId).Get(repoStatistic) | |||
| if err != nil { | |||
| return nil, err | |||
| } else { | |||
| if has { | |||
| return repoStatistic, nil | |||
| } else { | |||
| return nil, fmt.Errorf("The num of return records is 0.") | |||
| } | |||
| } | |||
| } | |||
| func GetRepoStatisticByDate(date string, repoId int64) ([]*RepoStatistic, error) { | |||
| repoStatistics := make([]*RepoStatistic, 0) | |||
| err := xStatistic.Where("date = ?", date).Find(&repoStatistics) | |||
| err := xStatistic.Where("date = ? and repo_id=?", date, repoId).Find(&repoStatistics) | |||
| return repoStatistics, err | |||
| } | |||
| @@ -159,7 +159,7 @@ func GenerateTask(ctx *context.Context, jobName, uuid, description string) error | |||
| JobID: jobResult.ID, | |||
| JobName: jobName, | |||
| JobType: string(models.JobTypeDebug), | |||
| Type: models.TypeCloudBrainNotebook, | |||
| Type: models.TypeCloudBrainTwo, | |||
| Uuid: uuid, | |||
| }) | |||
| @@ -195,17 +195,24 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) error { | |||
| return err | |||
| } | |||
| attach, err := models.GetAttachmentByUUID(req.Uuid) | |||
| if err != nil { | |||
| log.Error("GetAttachmentByUUID(%s) failed:%v", strconv.FormatInt(jobResult.JobID, 10), err.Error()) | |||
| return nil | |||
| } | |||
| 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.JobTypeDebug), | |||
| Type: models.TypeCloudBrainTrainJob, | |||
| JobType: string(models.JobTypeTrain), | |||
| Type: models.TypeCloudBrainTwo, | |||
| VersionID: jobResult.VersionID, | |||
| VersionName: jobResult.VersionName, | |||
| Uuid: req.Uuid, | |||
| DatasetName: attach.Name, | |||
| }) | |||
| if err != nil { | |||
| @@ -366,10 +366,6 @@ sendjob: | |||
| return &result, fmt.Errorf("json.Unmarshal failed(%s): %v", res.String(), err.Error()) | |||
| } | |||
| log.Error("createTrainJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||
| if res.StatusCode() == 400 { | |||
| temp.ErrorCode = "0404" | |||
| temp.ErrorMsg = "启动文件未找到!" | |||
| } | |||
| return &result, fmt.Errorf("createTrainJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) | |||
| } | |||
| @@ -544,6 +544,7 @@ var ( | |||
| GrowthContributors float64 | |||
| GrowthCommit float64 | |||
| GrowthComments float64 | |||
| RecordBeginTime string | |||
| }{} | |||
| ) | |||
| @@ -1324,6 +1325,7 @@ func SetRadarMapConfig() { | |||
| RadarMap.GrowthContributors = sec.Key("growth_contributors").MustFloat64(0.2) | |||
| RadarMap.GrowthCommit = sec.Key("growth_commit").MustFloat64(0.2) | |||
| RadarMap.GrowthComments = sec.Key("growth_comments").MustFloat64(0.2) | |||
| RadarMap.RecordBeginTime = sec.Key("record_beigin_time").MustString("2021-11-04") | |||
| } | |||
| @@ -764,15 +764,15 @@ submit_image=Submit Image | |||
| download=Download | |||
| cloudbrain=cloudbrain | |||
| cloudbrain=Cloudbrain | |||
| cloudbrain.new=New cloudbrain | |||
| cloudbrain.desc=cloudbrain | |||
| cloudbrain.desc=Cloudbrain | |||
| cloudbrain.cancel=Cancel | |||
| cloudbrain.commit_image = submit | |||
| clone_cnt=download | |||
| balance = balance | |||
| balance.total_view = total balance | |||
| balance.available = available balance: | |||
| cloudbrain.commit_image = Submit | |||
| clone_cnt=Download | |||
| balance = Balance | |||
| balance.total_view = Total Balance | |||
| balance.available = Available Balance: | |||
| cloudbrain1 = cloudbrain1 | |||
| cloudbrain2 = cloudbrain2 | |||
| cloudbrain_selection = select cloudbrain | |||
| @@ -785,13 +785,19 @@ cloudbrain_operate = Operate | |||
| cloudbrain_status_createtime = Status/Createtime | |||
| cloudbrain_status_runtime = Running Time | |||
| record_begintime_get_err=Can not get the record begin time. | |||
| parameter_is_wrong=The input parameter is wrong. | |||
| total_count_get_error=Can not get the total page. | |||
| last_update_time_error=Can not get the last updated time. | |||
| get_repo_stat_error=Can not get the statistics of the repository. | |||
| get_repo_info_error=Can not get the information of the repository. | |||
| modelarts.notebook=Debug Task | |||
| modelarts.train_job=Create Task | |||
| modelarts.train_job=Train Task | |||
| modelarts.train_job.new_debug= New Debug Task | |||
| modelarts.train_job.new_train=New Train Task | |||
| modelarts.train_job.config=Configuration information | |||
| modelarts.train_job.new=New train Task | |||
| modelarts.train_job.new_place=The description should not exceed 256 characters | |||
| @@ -787,22 +787,29 @@ cloudbrain_status_createtime=状态/创建时间 | |||
| cloudbrain_status_runtime = 运行时长 | |||
| cloudbrain_jobname_err=只能以小写字母或数字开头且只包含小写字母、数字、_和-,不能以_结尾,最长36个字符。 | |||
| record_begintime_get_err=无法获取统计开始时间。 | |||
| parameter_is_wrong=输入参数错误,请检查输入参数。 | |||
| total_count_get_error=查询总页数失败。 | |||
| last_update_time_error=查询最新更新时间失败。 | |||
| get_repo_stat_error=查询当前仓库的统计信息失败。 | |||
| get_repo_info_error=查询当前仓库信息失败。 | |||
| modelarts.notebook=调试任务 | |||
| modelarts.train_job=训练任务 | |||
| modelarts.train_job.new_debug=新建调试任务 | |||
| modelarts.train_job.new_train=新建训练任务 | |||
| modelarts.train_job.config=配置信息 | |||
| modelarts.train_job.new=新建训练任务 | |||
| modelarts.train_job.new_place=描述字数不超过256个字符 | |||
| modelarts.train_job.basic_info=基本信息 | |||
| modelarts.train_job.job_status=作业状态 | |||
| modelarts.train_job.job_name=作业名称 | |||
| modelarts.train_job.version=作业版本 | |||
| modelarts.train_job.job_status=任务状态 | |||
| modelarts.train_job.job_name=任务名称 | |||
| modelarts.train_job.version=任务版本 | |||
| modelarts.train_job.start_time=开始时间 | |||
| modelarts.train_job.dura_time=运行时长 | |||
| modelarts.train_job.description=作业描述 | |||
| modelarts.train_job.description=任务描述 | |||
| modelarts.train_job.parameter_setting=参数设置 | |||
| modelarts.train_job.parameter_setting_info=参数信息 | |||
| modelarts.train_job.fast_parameter_setting=一键式参数配置 | |||
| @@ -830,12 +837,12 @@ modelarts.train_job.query_whether_save_parameter=保存作业参数 | |||
| modelarts.train_job.save_helper=保存当前作业的配置参数,后续您可以使用已保存的配置参数快速创建训练作业。 | |||
| modelarts.train_job.common_frame=常用框架 | |||
| modelarts.train_job.amount_of_compute_node=计算节点个数 | |||
| modelarts.train_job.job_parameter_name=作业参数名称 | |||
| modelarts.train_job.parameter_description=作业参数描述 | |||
| modelarts.train_job.job_parameter_name=任务参数名称 | |||
| modelarts.train_job.parameter_description=任务参数描述 | |||
| modelarts.log=日志 | |||
| modelarts.version_manage=版本管理 | |||
| modelarts.back=返回 | |||
| modelarts.train_job_para_admin=作业参数管理 | |||
| modelarts.train_job_para_admin=任务参数管理 | |||
| modelarts.train_job_para.edit=编辑 | |||
| modelarts.train_job_para.connfirm=确定 | |||
| @@ -523,6 +523,19 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
| Get(notify.GetThread). | |||
| Patch(notify.ReadThread) | |||
| }, reqToken()) | |||
| adminReq := context.Toggle(&context.ToggleOptions{SignInRequired: true, AdminRequired: true}) | |||
| //Project board | |||
| m.Group("/projectboard", func() { | |||
| m.Group("/project", func() { | |||
| m.Get("", adminReq, repo.GetAllProjectsPeriodStatistics) | |||
| m.Group("/:id", func() { | |||
| m.Get("", adminReq, repo.GetProjectLatestStatistics) | |||
| m.Get("/period", adminReq, repo.GetProjectPeriodStatistics) | |||
| }) | |||
| }) | |||
| }) | |||
| // Users | |||
| m.Group("/users", func() { | |||
| @@ -0,0 +1,362 @@ | |||
| package repo | |||
| import ( | |||
| "fmt" | |||
| "net/http" | |||
| "strconv" | |||
| "time" | |||
| "code.gitea.io/gitea/models" | |||
| "code.gitea.io/gitea/modules/log" | |||
| "code.gitea.io/gitea/modules/context" | |||
| "code.gitea.io/gitea/modules/setting" | |||
| ) | |||
| const DEFAULT_PAGE_SIZE = 10 | |||
| const DATE_FORMAT = "2006-01-02" | |||
| type ProjectsPeriodData struct { | |||
| RecordBeginTime string `json:"recordBeginTime"` | |||
| LastUpdatedTime string `json:"lastUpdatedTime"` | |||
| PageSize int `json:"pageSize"` | |||
| TotalPage int `json:"totalPage"` | |||
| PageRecords []*models.RepoStatistic `json:"pageRecords"` | |||
| } | |||
| type UserInfo struct { | |||
| User string `json:"user"` | |||
| Mode int `json:"mode"` | |||
| PR int64 `json:"pr"` | |||
| Commit int `json:"commit"` | |||
| } | |||
| type ProjectLatestData struct { | |||
| RecordBeginTime string `json:"recordBeginTime"` | |||
| LastUpdatedTime string `json:"lastUpdatedTime"` | |||
| CreatTime string `json:"creatTime"` | |||
| OpenI float64 `json:"openi"` | |||
| Comment int64 `json:"comment"` | |||
| View int64 `json:"view"` | |||
| Download int64 `json:"download"` | |||
| IssueClosedRatio float32 `json:"issueClosedRatio"` | |||
| Impact float64 `json:"impact"` | |||
| Completeness float64 `json:"completeness"` | |||
| Liveness float64 `json:"liveness"` | |||
| ProjectHealth float64 `json:"projectHealth"` | |||
| TeamHealth float64 `json:"teamHealth"` | |||
| Growth float64 `json:"growth"` | |||
| Description string `json:"description"` | |||
| Top10 []UserInfo `json:"top10"` | |||
| } | |||
| func GetAllProjectsPeriodStatistics(ctx *context.Context) { | |||
| recordBeginTime, err := getRecordBeginTime() | |||
| if err != nil { | |||
| log.Error("Can not get record begin time", err) | |||
| ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err")) | |||
| return | |||
| } | |||
| beginTime, endTime, err := getTimePeroid(ctx, recordBeginTime) | |||
| if err != nil { | |||
| log.Error("Parameter is wrong", err) | |||
| ctx.Error(http.StatusBadRequest, ctx.Tr("repo.parameter_is_wrong")) | |||
| return | |||
| } | |||
| q := ctx.QueryTrim("q") | |||
| page := ctx.QueryInt("page") | |||
| if page <= 0 { | |||
| page = 1 | |||
| } | |||
| pageSize := ctx.QueryInt("pagesize") | |||
| if pageSize <= 0 { | |||
| pageSize = DEFAULT_PAGE_SIZE | |||
| } | |||
| orderBy := getOrderBy(ctx) | |||
| latestUpdatedTime, latestDate, err := models.GetRepoStatLastUpdatedTime() | |||
| if err != nil { | |||
| log.Error("Can not query the last updated time.", err) | |||
| ctx.Error(http.StatusBadRequest, ctx.Tr("repo.last_update_time_error")) | |||
| return | |||
| } | |||
| countSql := generateCountSql(beginTime, endTime, latestDate, q) | |||
| total, err := models.CountRepoStatByRawSql(countSql) | |||
| if err != nil { | |||
| log.Error("Can not query total count.", err) | |||
| ctx.Error(http.StatusBadRequest, ctx.Tr("repo.total_count_get_error")) | |||
| return | |||
| } | |||
| projectsPeriodData := ProjectsPeriodData{ | |||
| RecordBeginTime: recordBeginTime.Format(DATE_FORMAT), | |||
| PageSize: pageSize, | |||
| TotalPage: getTotalPage(total, pageSize), | |||
| LastUpdatedTime: latestUpdatedTime, | |||
| PageRecords: models.GetRepoStatisticByRawSql(generatePageSql(beginTime, endTime, latestDate, q, orderBy, page, pageSize)), | |||
| } | |||
| ctx.JSON(http.StatusOK, projectsPeriodData) | |||
| } | |||
| func GetProjectLatestStatistics(ctx *context.Context) { | |||
| repoId := ctx.Params(":id") | |||
| recordBeginTime, err := getRecordBeginTime() | |||
| if err != nil { | |||
| log.Error("Can not get record begin time", err) | |||
| ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err")) | |||
| return | |||
| } | |||
| latestUpdatedTime, latestDate, err := models.GetRepoStatLastUpdatedTime(repoId) | |||
| repoIdInt, _ := strconv.ParseInt(repoId, 10, 64) | |||
| repoStat, err := models.GetRepoStatisticByDateAndRepoId(latestDate, repoIdInt) | |||
| if err != nil { | |||
| log.Error("Can not get the repo statistics "+repoId, err) | |||
| ctx.Error(http.StatusBadRequest, ctx.Tr("repo.get_repo_stat_error")) | |||
| return | |||
| } | |||
| repository, err := models.GetRepositoryByID(repoIdInt) | |||
| if err != nil { | |||
| log.Error("Can not get the repo info "+repoId, err) | |||
| ctx.Error(http.StatusBadRequest, ctx.Tr("repo.get_repo_info_error")) | |||
| return | |||
| } | |||
| projectLatestData := ProjectLatestData{ | |||
| RecordBeginTime: recordBeginTime.Format(DATE_FORMAT), | |||
| CreatTime: time.Unix(int64(repository.CreatedUnix), 0).Format(DATE_FORMAT), | |||
| LastUpdatedTime: latestUpdatedTime, | |||
| OpenI: repoStat.RadarTotal, | |||
| Comment: repoStat.NumComments, | |||
| View: repoStat.NumVisits, | |||
| Download: repoStat.NumDownloads, | |||
| IssueClosedRatio: repoStat.IssueFixedRate, | |||
| Impact: repoStat.Impact, | |||
| Completeness: repoStat.Completeness, | |||
| Liveness: repoStat.Liveness, | |||
| ProjectHealth: repoStat.ProjectHealth, | |||
| TeamHealth: repoStat.TeamHealth, | |||
| Growth: repoStat.Growth, | |||
| Description: repository.Description, | |||
| } | |||
| contributors, err := models.GetTop10Contributor(repository.RepoPath()) | |||
| if err != nil { | |||
| log.Error("can not get contributors", err) | |||
| } | |||
| users := make([]UserInfo, 0) | |||
| for _, contributor := range contributors { | |||
| mode := repository.GetCollaboratorMode(contributor.UserId) | |||
| pr := models.GetPullCountByUserAndRepoId(repoIdInt, contributor.UserId) | |||
| userInfo := UserInfo{ | |||
| User: contributor.Committer, | |||
| Commit: contributor.CommitCnt, | |||
| Mode: mode, | |||
| PR: pr, | |||
| } | |||
| users = append(users, userInfo) | |||
| } | |||
| projectLatestData.Top10 = users | |||
| ctx.JSON(http.StatusOK, projectLatestData) | |||
| } | |||
| func GetProjectPeriodStatistics(ctx *context.Context) { | |||
| repoId := ctx.Params(":id") | |||
| recordBeginTime, err := getRecordBeginTime() | |||
| if err != nil { | |||
| log.Error("Can not get record begin time", err) | |||
| ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err")) | |||
| return | |||
| } | |||
| repoIdInt, _ := strconv.ParseInt(repoId, 10, 64) | |||
| if err != nil { | |||
| log.Error("Can not get record begin time", err) | |||
| ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err")) | |||
| return | |||
| } | |||
| beginTime, endTime, err := getTimePeroid(ctx, recordBeginTime) | |||
| isOpenI := ctx.QueryBool("openi") | |||
| var repositorys []*models.RepoStatistic | |||
| if isOpenI { | |||
| repositorys = models.GetRepoStatisticByRawSql(generateRadarSql(beginTime, endTime, repoIdInt)) | |||
| } else { | |||
| repositorys = models.GetRepoStatisticByRawSql(generateTargetSql(beginTime, endTime, repoIdInt)) | |||
| } | |||
| ctx.JSON(http.StatusOK, repositorys) | |||
| } | |||
| func generateRadarSql(beginTime time.Time, endTime time.Time, repoId int64) string { | |||
| sql := "SELECT date, impact, completeness, liveness, project_health, team_health, growth, radar_total FROM repo_statistic" + | |||
| " where repo_id=" + strconv.FormatInt(repoId, 10) + " and created_unix >=" + strconv.FormatInt(beginTime.Unix(), 10) + | |||
| " and created_unix<" + strconv.FormatInt(endTime.Unix(), 10) | |||
| return sql | |||
| } | |||
| func generateTargetSql(beginTime time.Time, endTime time.Time, repoId int64) string { | |||
| sql := "SELECT date, num_visits,num_downloads,num_commits FROM repo_statistic" + | |||
| " where repo_id=" + strconv.FormatInt(repoId, 10) + " and created_unix >=" + strconv.FormatInt(beginTime.Unix(), 10) + | |||
| " and created_unix<" + strconv.FormatInt(endTime.Unix(), 10) | |||
| return sql | |||
| } | |||
| func generateCountSql(beginTime time.Time, endTime time.Time, yesterday string, q string) string { | |||
| countSql := "SELECT count(*) FROM " + | |||
| "(SELECT repo_id FROM repo_statistic where created_unix >=" + strconv.FormatInt(beginTime.Unix(), 10) + | |||
| " and created_unix<" + strconv.FormatInt(endTime.Unix(), 10) + " group by repo_id) A," + | |||
| "(SELECT repo_id,name,is_private,radar_total from public.repo_statistic where date='" + yesterday + "') B" + | |||
| " where A.repo_id=B.repo_id" | |||
| if q != "" { | |||
| countSql = countSql + " and B.name like '%" + q + "%'" | |||
| } | |||
| return countSql | |||
| } | |||
| func generatePageSql(beginTime time.Time, endTime time.Time, yesterday string, q string, orderBy string, page int, pageSize int) string { | |||
| countSql := "SELECT A.repo_id,name,is_private,radar_total,num_watches,num_visits,num_downloads,num_pulls,num_commits,num_stars,num_forks,num_issues,num_closed_issues,num_contributor FROM " + | |||
| "(SELECT repo_id,sum(num_watches_added) as num_watches,sum(num_visits) as num_visits, sum(num_downloads_added) as num_downloads,sum(num_pulls_added) as num_pulls,sum(num_commits_added) as num_commits,sum(num_stars_added) as num_stars,sum(num_forks_added) num_forks,sum(num_issues_added) as num_issues,sum(num_closed_issues_added) as num_closed_issues,sum(num_contributor_added) as num_contributor " + | |||
| " FROM repo_statistic where created_unix >=" + strconv.FormatInt(beginTime.Unix(), 10) + | |||
| " and created_unix<" + strconv.FormatInt(endTime.Unix(), 10) + " group by repo_id) A," + | |||
| "(SELECT repo_id,name,is_private,radar_total from public.repo_statistic where date='" + yesterday + "') B" + | |||
| " where A.repo_id=B.repo_id" | |||
| if q != "" { | |||
| countSql = countSql + " and B.name like '%" + q + "%'" | |||
| } | |||
| countSql = countSql + " order by " + orderBy + " desc,A.repo_id" + " limit " + strconv.Itoa(pageSize) + " offset " + strconv.Itoa((page-1)*pageSize) | |||
| return countSql | |||
| } | |||
| func getOrderBy(ctx *context.Context) string { | |||
| orderBy := "" | |||
| switch ctx.Query("sort") { | |||
| case "openi": | |||
| orderBy = "B.radar_total" | |||
| case "view": | |||
| orderBy = "A.num_visits" | |||
| case "download": | |||
| orderBy = "A.num_downloads" | |||
| case "pr": | |||
| orderBy = "A.num_pulls" | |||
| case "commit": | |||
| orderBy = "A.num_commits" | |||
| case "watch": | |||
| orderBy = "A.num_watches" | |||
| case "star": | |||
| orderBy = "A.num_stars" | |||
| case "fork": | |||
| orderBy = "A.num_forks" | |||
| case "issue": | |||
| orderBy = "A.num_issues" | |||
| case "issue_closed": | |||
| orderBy = "A.num_closed_issues" | |||
| case "contributor": | |||
| orderBy = "A.num_contributor" | |||
| default: | |||
| orderBy = "B.radar_total" | |||
| } | |||
| return orderBy | |||
| } | |||
| func getTimePeroid(ctx *context.Context, recordBeginTime time.Time) (time.Time, time.Time, error) { | |||
| queryType := ctx.QueryTrim("type") | |||
| now := time.Now() | |||
| recordBeginTimeTemp := recordBeginTime.AddDate(0, 0, 1) | |||
| beginTimeStr := ctx.QueryTrim("beginTime") | |||
| endTimeStr := ctx.QueryTrim("endTime") | |||
| var beginTime time.Time | |||
| var endTime time.Time | |||
| if queryType != "" { | |||
| if queryType == "all" { | |||
| beginTime = recordBeginTimeTemp | |||
| endTime = now | |||
| } else if queryType == "yesterday" { | |||
| endTime = now | |||
| beginTime = time.Date(endTime.Year(), endTime.Month(), endTime.Day(), 0, 0, 0, 0, now.Location()) | |||
| } else if queryType == "current_week" { | |||
| beginTime = now.AddDate(0, 0, -int(time.Now().Weekday())+1) | |||
| beginTime = time.Date(beginTime.Year(), beginTime.Month(), beginTime.Day(), 0, 0, 0, 0, now.Location()) | |||
| endTime = now | |||
| } else if queryType == "current_month" { | |||
| endTime = now | |||
| beginTime = time.Date(endTime.Year(), endTime.Month(), 2, 0, 0, 0, 0, now.Location()) | |||
| } else if queryType == "monthly" { | |||
| endTime = now | |||
| beginTime = now.AddDate(0, -1, 1) | |||
| beginTime = time.Date(beginTime.Year(), beginTime.Month(), beginTime.Day(), 0, 0, 0, 0, now.Location()) | |||
| } else if queryType == "current_year" { | |||
| endTime = now | |||
| beginTime = time.Date(endTime.Year(), 1, 2, 0, 0, 0, 0, now.Location()) | |||
| } else if queryType == "last_month" { | |||
| lastMonthTime := now.AddDate(0, -1, 0) | |||
| beginTime = time.Date(lastMonthTime.Year(), lastMonthTime.Month(), 2, 0, 0, 0, 0, now.Location()) | |||
| endTime = time.Date(now.Year(), now.Month(), 2, 0, 0, 0, 0, now.Location()) | |||
| } else { | |||
| return now, now, fmt.Errorf("The value of type parameter is wrong.") | |||
| } | |||
| } else { | |||
| if beginTimeStr == "" || endTimeStr == "" { | |||
| //如果查询类型和开始时间结束时间都未设置,按queryType=all处理 | |||
| beginTime = recordBeginTimeTemp | |||
| endTime = now | |||
| } else { | |||
| beginTime, err := time.Parse("2006-01-02", beginTimeStr) | |||
| if err != nil { | |||
| return now, now, err | |||
| } | |||
| endTime, err := time.Parse("2006-01-02", endTimeStr) | |||
| if err != nil { | |||
| return now, now, err | |||
| } | |||
| beginTime = beginTime.AddDate(0, 0, 1) | |||
| endTime = endTime.AddDate(0, 0, 1) | |||
| } | |||
| } | |||
| if beginTime.Before(recordBeginTimeTemp) { | |||
| beginTime = recordBeginTimeTemp | |||
| } | |||
| return beginTime, endTime, nil | |||
| } | |||
| func getRecordBeginTime() (time.Time, error) { | |||
| return time.Parse(DATE_FORMAT, setting.RadarMap.RecordBeginTime) | |||
| } | |||
| func getTotalPage(total int64, pageSize int) int { | |||
| another := 0 | |||
| if int(total)%pageSize != 0 { | |||
| another = 1 | |||
| } | |||
| return int(total)/pageSize + another | |||
| } | |||
| @@ -146,7 +146,7 @@ func RenderRepoSearch(ctx *context.Context, opts *RepoSearchOptions) { | |||
| ctx.Data["SortType"] = "hot" | |||
| orderBy = models.SearchOrderByHot | |||
| } | |||
| orderBy = orderBy + ",id" | |||
| //todo:support other topics | |||
| keyword := strings.Trim(ctx.Query("q"), " ") | |||
| topic := strings.Trim(ctx.Query("topic"), " ") | |||
| @@ -917,16 +917,22 @@ func HandleUnDecompressAttachment() { | |||
| } | |||
| for _, attach := range attachs { | |||
| err = worker.SendDecompressTask(contexExt.Background(), attach.UUID, attach.Name) | |||
| if err != nil { | |||
| log.Error("SendDecompressTask(%s) failed:%s", attach.UUID, err.Error()) | |||
| } else { | |||
| attach.DecompressState = models.DecompressStateIng | |||
| err = models.UpdateAttachment(attach) | |||
| if attach.Type == models.TypeCloudBrainOne { | |||
| err = worker.SendDecompressTask(contexExt.Background(), attach.UUID, attach.Name) | |||
| if err != nil { | |||
| log.Error("UpdateAttachment state(%s) failed:%s", attach.UUID, err.Error()) | |||
| log.Error("SendDecompressTask(%s) failed:%s", attach.UUID, err.Error()) | |||
| } else { | |||
| attach.DecompressState = models.DecompressStateIng | |||
| err = models.UpdateAttachment(attach) | |||
| if err != nil { | |||
| log.Error("UpdateAttachment state(%s) failed:%s", attach.UUID, err.Error()) | |||
| } | |||
| } | |||
| } else if attach.Type == models.TypeCloudBrainTwo { | |||
| attachjson, _ := json.Marshal(attach) | |||
| labelmsg.SendDecompressAttachToLabelOBS(string(attachjson)) | |||
| } | |||
| } | |||
| return | |||
| @@ -1014,7 +1020,7 @@ func queryDatasets(ctx *context.Context, attachs []*models.AttachmentUsername) { | |||
| } | |||
| func checkTypeCloudBrain(typeCloudBrain int) error { | |||
| if typeCloudBrain != models.TypeCloudBrainOne && typeCloudBrain != models.TypeCloudBrainNotebook { | |||
| if typeCloudBrain != models.TypeCloudBrainOne && typeCloudBrain != models.TypeCloudBrainTwo { | |||
| log.Error("type error:", typeCloudBrain) | |||
| return errors.New("type error") | |||
| } | |||
| @@ -4,6 +4,7 @@ import ( | |||
| "encoding/json" | |||
| "errors" | |||
| "io" | |||
| "io/ioutil" | |||
| "net/http" | |||
| "os" | |||
| "path" | |||
| @@ -35,10 +36,10 @@ const ( | |||
| tplModelArtsNew base.TplName = "repo/modelarts/new" | |||
| tplModelArtsShow base.TplName = "repo/modelarts/show" | |||
| tplModelArtsTrainJobIndex base.TplName = "repo/modelarts/trainjob/index" | |||
| tplModelArtsTrainJobNew base.TplName = "repo/modelarts/trainjob/new" | |||
| tplModelArtsTrainJobShow base.TplName = "repo/modelarts/trainjob/show" | |||
| tplModelArtsTrainJobShowModels base.TplName = "repo/modelarts/trainjob/models/index" | |||
| tplModelArtsTrainJobIndex base.TplName = "repo/modelarts/trainjob/index" | |||
| tplModelArtsTrainJobNew base.TplName = "repo/modelarts/trainjob/new" | |||
| tplModelArtsTrainJobShow base.TplName = "repo/modelarts/trainjob/show" | |||
| tplModelArtsTrainJobShowModels base.TplName = "repo/modelarts/trainjob/models/index" | |||
| ) | |||
| // MustEnableDataset check if repository enable internal cb | |||
| @@ -286,7 +287,8 @@ func NotebookIndex(ctx *context.Context) { | |||
| PageSize: setting.UI.IssuePagingNum, | |||
| }, | |||
| RepoID: repo.ID, | |||
| Type: models.TypeCloudBrainNotebook, | |||
| Type: models.TypeCloudBrainTwo, | |||
| JobType: string(models.JobTypeDebug), | |||
| }) | |||
| if err != nil { | |||
| ctx.ServerError("Cloudbrain", err) | |||
| @@ -511,7 +513,8 @@ func TrainJobIndex(ctx *context.Context) { | |||
| PageSize: setting.UI.IssuePagingNum, | |||
| }, | |||
| RepoID: repo.ID, | |||
| Type: models.TypeCloudBrainTrainJob, | |||
| Type: models.TypeCloudBrainTwo, | |||
| JobType: string(models.JobTypeTrain), | |||
| }) | |||
| if err != nil { | |||
| ctx.ServerError("Cloudbrain", err) | |||
| @@ -621,7 +624,7 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||
| codeObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.CodePath | |||
| outputObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.OutputPath | |||
| logObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.LogPath | |||
| dataPath := "/" + setting.Bucket + "/" + setting.BasePath + path.Join(uuid[0:1], uuid[1:2]) + "/" + uuid + "/" | |||
| dataPath := "/" + setting.Bucket + "/" + setting.BasePath + path.Join(uuid[0:1], uuid[1:2]) + "/" + uuid + uuid + "/" | |||
| //can, err := canUserCreateTrainJob(ctx.User.ID) | |||
| //if err != nil { | |||
| @@ -643,10 +646,29 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||
| return | |||
| } | |||
| attach, err := models.GetAttachmentByUUID(uuid) | |||
| if err != nil { | |||
| log.Error("GetAttachmentByUUID(%s) failed:%v", uuid, err.Error()) | |||
| return | |||
| } | |||
| //todo: del the codeLocalPath | |||
| _, err = ioutil.ReadDir(codeLocalPath) | |||
| if err == nil { | |||
| os.RemoveAll(codeLocalPath) | |||
| } | |||
| if err := git.Clone(repo.RepoPath(), codeLocalPath, git.CloneRepoOptions{}); err != nil { | |||
| log.Error("Failed to clone repository: %s (%v)", repo.FullName(), err) | |||
| log.Error("创建任务失败,任务名称已存在!: %s (%v)", repo.FullName(), err) | |||
| trainJobNewDataPrepare(ctx) | |||
| ctx.RenderWithErr("Failed to clone repository", tplModelArtsTrainJobNew, &form) | |||
| ctx.Data["bootFile"] = form.BootFile | |||
| ctx.Data["uuid"] = form.Attachment | |||
| ctx.Data["datasetName"] = attach.Name | |||
| ctx.Data["params"] = form.Params | |||
| trainJobNewDataPrepare(ctx) | |||
| // ctx.RenderWithErr("Failed to clone repository", tplModelArtsTrainJobNew, &form) | |||
| ctx.RenderWithErr("创建任务失败,任务名称已存在!", tplModelArtsTrainJobNew, &form) | |||
| // ctx.RenderWithErr(err, tplModelArtsTrainJobNew, &form) | |||
| return | |||
| } | |||
| @@ -752,10 +774,14 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||
| Parameters: param, | |||
| } | |||
| err := modelarts.GenerateTrainJob(ctx, req) | |||
| err = modelarts.GenerateTrainJob(ctx, req) | |||
| if err != nil { | |||
| log.Error("GenerateTrainJob failed:%v", err.Error()) | |||
| trainJobNewDataPrepare(ctx) | |||
| ctx.Data["bootFile"] = form.BootFile | |||
| ctx.Data["uuid"] = form.Attachment | |||
| ctx.Data["datasetName"] = attach.Name | |||
| ctx.Data["params"] = form.Params | |||
| ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobNew, &form) | |||
| return | |||
| } | |||
| @@ -860,12 +886,12 @@ func TrainJobShow(ctx *context.Context) { | |||
| return | |||
| } | |||
| attach, err := models.GetAttachmentByUUID(task.Uuid) | |||
| if err != nil { | |||
| log.Error("GetAttachmentByUUID(%s) failed:%v", jobID, err.Error()) | |||
| ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobShow, nil) | |||
| return | |||
| } | |||
| // 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 | |||
| // } | |||
| result, err := modelarts.GetTrainJob(jobID, strconv.FormatInt(task.VersionID, 10)) | |||
| if err != nil { | |||
| @@ -889,7 +915,7 @@ func TrainJobShow(ctx *context.Context) { | |||
| return | |||
| } | |||
| result.DatasetName = attach.Name | |||
| result.DatasetName = task.DatasetName | |||
| } | |||
| resultLogFile, resultLog, err := trainJobGetLog(jobID) | |||
| @@ -115,7 +115,7 @@ func RepoStatisticDaily(date string) { | |||
| } | |||
| dayBeforeDate := t.AddDate(0, 0, -1).Format("2006-01-02") | |||
| repoStatisticsBefore, err := models.GetRepoStatisticByDate(dayBeforeDate) | |||
| repoStatisticsBefore, err := models.GetRepoStatisticByDate(dayBeforeDate, repo.ID) | |||
| if err != nil { | |||
| log.Error("get data of day before the date failed ", err) | |||
| @@ -324,7 +324,7 @@ | |||
| <form id="stopForm-{{.JobID}}" action="{{$.Link}}/{{.JobID}}/stop" method="post" style="margin-left:-1px;"> | |||
| {{$.CsrfTokenHtml}} | |||
| {{if $.Permission.CanWrite $.UnitTypeCloudBrain}} | |||
| <a id="stop-model-debug-{{.JobID}}" style="margin-right: 2rem;" class="ui basic {{if or (eq .Status "STOPPED") (eq .Status "FAILED") (eq .Status "START_FAILED")}}disabled {{else}}blue {{end}}button" onclick="document.getElementById('stopForm-{{.JobID}}').submit();"> | |||
| <a id="stop-model-debug-{{.JobID}}" style="margin-right: 2rem;" class="ui basic {{if eq .Status "STOPPED" "FAILED" "START_FAILED" "STOPPING" "CREATING" "WAITING" "STARTING"}}disabled {{else}}blue {{end}}button" onclick="document.getElementById('stopForm-{{.JobID}}').submit();"> | |||
| {{$.i18n.Tr "repo.stop"}} | |||
| </a> | |||
| {{else}} | |||
| @@ -352,7 +352,7 @@ | |||
| <form class="ui compact buttons" id="delForm-{{.JobID}}" action="{{$.Link}}/{{.JobID}}/del" method="post"> | |||
| {{$.CsrfTokenHtml}} | |||
| {{if $.Permission.CanWrite $.UnitTypeCloudBrain}} | |||
| <a id="model-delete-{{.JobID}}" class="ui compact {{if eq .Status "RUNNING"}}disabled {{else}}red {{end}}button" onclick="assertDelete(this)" style="border-radius: .28571429rem;"> | |||
| <a id="model-delete-{{.JobID}}" class="ui compact {{if eq .Status "RUNNING" "CREATING" "WAITING" "STARTING" "STOPPING" }}disabled {{else}}red {{end}}button" onclick="assertDelete(this)" style="border-radius: .28571429rem;"> | |||
| {{$.i18n.Tr "repo.delete"}} | |||
| </a> | |||
| {{else}} | |||
| @@ -477,10 +477,10 @@ | |||
| } | |||
| if(status!=="STOPPED" || status!=="FAILED"){ | |||
| $('#stop-model-debug-'+jobID).removeClass('disabled') | |||
| $('#stop-model-debug-'+jobID).addClass('blue') | |||
| $('#model-delete-'+jobID).removeClass('red') | |||
| $('#model-delete-'+jobID).addClass('disabled') | |||
| // $('#stop-model-debug-'+jobID).removeClass('disabled') | |||
| // $('#stop-model-debug-'+jobID).addClass('blue') | |||
| // $('#model-delete-'+jobID).removeClass('red') | |||
| // $('#model-delete-'+jobID).addClass('disabled') | |||
| } | |||
| if(status=="STOPPED" || status=="FAILED" ){ | |||
| $('#stop-model-debug-'+jobID).removeClass('blue') | |||
| @@ -491,6 +491,8 @@ | |||
| if(status=="START_FAILED"){ | |||
| $('#stop-model-debug-'+jobID).removeClass('blue') | |||
| $('#stop-model-debug-'+jobID).addClass('disabled') | |||
| $('#model-delete-'+jobID).removeClass('disabled') | |||
| $('#model-delete-'+jobID).addClass('red') | |||
| } | |||
| }).fail(function(err) { | |||
| console.log(err); | |||
| @@ -291,7 +291,7 @@ | |||
| <span>{{$.i18n.Tr "repo.cloudbrain_creator"}}</span> | |||
| </div> | |||
| <div class="five wide column text center"> | |||
| <span>{{$.i18n.Tr "repo.cloudbrain_operate"}}</span> | |||
| <span style="margin-left: 6rem;">{{$.i18n.Tr "repo.cloudbrain_operate"}}</span> | |||
| </div> | |||
| </div> | |||
| @@ -355,7 +355,7 @@ | |||
| <form id="stopForm-{{.JobID}}" action="{{$.Link}}/{{.JobID}}/stop" method="post" style="margin-left:-1px;"> | |||
| {{$.CsrfTokenHtml}} | |||
| {{if $.Permission.CanWrite $.UnitTypeCloudBrain}} | |||
| <a id="stop-model-debug-{{.JobID}}" class="ui basic {{if or (eq .Status "KILLED") (eq .Status "FAILED") (eq .Status "START_FAILED")}}disabled {{else}}blue {{end}}button" onclick="document.getElementById('stopForm-{{.JobID}}').submit();"> | |||
| <a id="stop-model-debug-{{.JobID}}" class="ui basic {{if eq .Status "KILLED" "FAILED" "START_FAILED" "KILLING" "COMPLETED"}}disabled {{else}}blue {{end}}button" onclick="document.getElementById('stopForm-{{.JobID}}').submit();"> | |||
| {{$.i18n.Tr "repo.stop"}} | |||
| </a> | |||
| {{else}} | |||
| @@ -380,7 +380,7 @@ | |||
| <form class="ui compact buttons" id="delForm-{{.JobID}}" action="{{$.Link}}/{{.JobID}}/del" method="post"> | |||
| {{$.CsrfTokenHtml}} | |||
| {{if $.Permission.CanWrite $.UnitTypeCloudBrain}} | |||
| <a id="model-delete-{{.JobID}}" class="ui compact {{if eq .Status "RUNNING" }}disabled {{else}}red {{end}}button" onclick="assertDelete(this)" style="border-radius: .28571429rem;"> | |||
| <a id="model-delete-{{.JobID}}" class="ui compact {{if or (eq .Status "RUNNING") (eq .Status "INIT") (eq .Status "CREATING") (eq .Status "WAITING") }}disabled {{else}}red {{end}}button" onclick="assertDelete(this)" style="border-radius: .28571429rem;"> | |||
| {{$.i18n.Tr "repo.delete"}} | |||
| </a> | |||
| {{else}} | |||
| @@ -535,7 +535,7 @@ | |||
| $('#model-delete-'+jobID).removeClass('red') | |||
| $('#model-delete-'+jobID).addClass('disabled') | |||
| } | |||
| if(status=="KILLED" || status=="FAILED"){ | |||
| if(status=="KILLED" || status=="FAILED" || status=="KILLING"){ | |||
| $('#stop-model-debug-'+jobID).removeClass('blue') | |||
| $('#stop-model-debug-'+jobID).addClass('disabled') | |||
| $('#model-delete-'+jobID).removeClass('disabled') | |||
| @@ -156,16 +156,12 @@ | |||
| <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 style="width: 80%;" name="job_name" id="trainjob_job_name" placeholder={{.i18n.Tr "repo.modelarts.train_job.job_name"}} value="{{.job_name}}" tabindex="3" autofocus required maxlength="255"> | |||
| <input style="width: 60%;" name="job_name" id="trainjob_job_name" placeholder={{.i18n.Tr "repo.modelarts.train_job.job_name"}} value="{{.job_name}}" tabindex="3" autofocus required maxlength="255"> | |||
| </div> | |||
| <!--<div class="inline field"> | |||
| <label>{{.i18n.Tr "repo.modelarts.train_job.version"}}</label> | |||
| <span>第一版本</span> | |||
| </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" name="description" rows="3" maxlength="256" placeholder="描述字符不超过256个字符" onchange="this.value=this.value.substring(0, 256)" onkeydown="this.value=this.value.substring(0, 256)" onkeyup="this.value=this.value.substring(0, 256)"></textarea> | |||
| <textarea style="width: 80%;" id="description" name="description" rows="3" maxlength="255" placeholder={{.i18n.Tr "repo.modelarts.train_job.new_place"}} onchange="this.value=this.value.substring(0, 255)" onkeydown="this.value=this.value.substring(0, 255)" onkeyup="this.value=this.value.substring(0, 256)"></textarea> | |||
| </div> | |||
| <!-- <h4 class="ui dividing header">{{.i18n.Tr "repo.modelarts.train_job.parameter_setting"}}</h4> | |||
| <div class="inline field"> | |||
| @@ -182,7 +178,7 @@ | |||
| <div class="required unite min_title inline fields" style="width: 90%;"> | |||
| <label>{{.i18n.Tr "repo.modelarts.train_job.AI_driver"}} </label> | |||
| <div class="field" style="flex: 1.5;"> | |||
| <select class="ui search dropdown width" id="trainjob_engines" > | |||
| <select class="ui dropdown width" id="trainjob_engines" > | |||
| {{range .engines}} | |||
| <option value="{{.Value}}">{{.Value}}</option> | |||
| {{end}} | |||
| @@ -190,7 +186,7 @@ | |||
| </div> | |||
| <div class="field" style="flex: 2;"> | |||
| <select class="ui search dropdown width" id="trainjob_engine_versions" style='width: 100%;' name="engine_id"> | |||
| <select class="ui dropdown width" id="trainjob_engine_versions" style='width: 100%;' name="engine_id"> | |||
| {{range .engine_versions}} | |||
| <option name="engine_id" value="{{.ID}}">{{.Value}}</option> | |||
| {{end}} | |||
| @@ -235,20 +231,28 @@ | |||
| </div> --> | |||
| <div class="inline unite min_title field required"> | |||
| <label>{{.i18n.Tr "repo.modelarts.train_job.start_file"}}</label> | |||
| <input style="width: 33.5%;" name="boot_file" id="trainjob_boot_file" value="" tabindex="3" autofocus required maxlength="255" > | |||
| {{if .bootFile}} | |||
| <input style="width: 33.5%;" name="boot_file" id="trainjob_boot_file" value="{{.bootFile}}" tabindex="3" autofocus required maxlength="255" > | |||
| {{else}} | |||
| <input style="width: 33.5%;" name="boot_file" id="trainjob_boot_file" value="" tabindex="3" autofocus required maxlength="255" > | |||
| {{end}} | |||
| <span> | |||
| <i class="question circle icon link" data-content={{.i18n.Tr "repo.modelarts.train_job.boot_file_helper"}} data-position="right center" data-variation="mini"></i> | |||
| </span> | |||
| </div> | |||
| <div class="required unite min_title inline field"> | |||
| <label>{{.i18n.Tr "repo.modelarts.train_job.dataset"}}</label> | |||
| <select class="ui search dropdown width80" id="trainjob_datasets" name="attachment"> | |||
| <select class="ui dropdown width80" id="trainjob_datasets" name="attachment" placeholder="选择数据集"> | |||
| {{if $.uuid}} | |||
| <option name="attachment" value="{{$.uuid}}">{{$.datasetName}}</option> | |||
| {{end}} | |||
| {{range .attachments}} | |||
| <option value="">选择数据集</option> | |||
| <option name="attachment" value="{{.UUID}}">{{.Attachment.Name}}</option> | |||
| {{end}} | |||
| </select> | |||
| </div> | |||
| <div class="inline unite min_title field"> | |||
| <label>{{.i18n.Tr "repo.modelarts.train_job.run_parameter"}}</label> | |||
| <!-- <i class="plus square outline icon"></i> --> | |||
| @@ -263,7 +267,7 @@ | |||
| <!-- <h4 class="ui dividing header">{{.i18n.Tr "repo.modelarts.train_job.resource_setting"}}</h4> --> | |||
| <div class="required field " style="display: none;"> | |||
| <label>{{.i18n.Tr "repo.modelarts.train_job.resource_pool"}}</label> | |||
| <select class="ui search dropdown" id="trainjob_resource_pool" style='width:385px' name="pool_id"> | |||
| <select class="ui dropdown" id="trainjob_resource_pool" style='width:385px' name="pool_id"> | |||
| {{range .resource_pools}} | |||
| <option value="{{.ID}}">{{.Value}}</option> | |||
| {{end}} | |||
| @@ -288,7 +292,7 @@ | |||
| <div class="required unite min_title inline field"> | |||
| <label>{{.i18n.Tr "repo.modelarts.train_job.standard"}}</label> | |||
| <select class="ui search dropdown width81" id="trainjob-flavor" style='width:385px' name="flavor"> | |||
| <select class="ui dropdown width81" id="trainjob-flavor" style='width:385px' name="flavor"> | |||
| {{range .flavor_infos}} | |||
| <option name="flavor" value="{{.Code}}">{{.Value}}</option> | |||
| {{end}} | |||
| @@ -297,11 +301,11 @@ | |||
| <div class="inline required unite min_title field"> | |||
| <label>{{.i18n.Tr "repo.modelarts.train_job.amount_of_compute_node"}}</label> | |||
| <div class="ui labeled input"> | |||
| <span class="min"><i class="minus icon"></i></span> | |||
| <input style="border-radius: 0;" name="work_server_number" id="trainjob_work_server_num" tabindex="3" autofocus required maxlength="255" value="1"> | |||
| <div class="ui labeled input" style="width: 5%;"> | |||
| <!-- <span class="min"><i class="minus icon"></i></span> --> | |||
| <input style="border-radius: 0;text-align: center;" name="work_server_number" id="trainjob_work_server_num" tabindex="3" autofocus required maxlength="255" value="1" readonly> | |||
| <span class="add"><i class="plus icon"></i></span> | |||
| <!-- <span class="add"><i class="plus icon"></i></span> --> | |||
| </div> | |||
| <!-- <input name="work_server_number" id="trainjob_work_server_num" tabindex="3" autofocus required maxlength="255"> --> | |||
| </div> | |||
| @@ -356,6 +360,9 @@ | |||
| let sever_num = $('#trainjob_work_server_num') | |||
| $('.add').click(function(){ | |||
| sever_num.val(parseInt(sever_num.val())+1) | |||
| if(sever_num.val()>=26){ | |||
| sever_num.val(parseInt(sever_num.val())-1) | |||
| } | |||
| }) | |||
| $('.min').click(function(){ | |||
| sever_num.val(parseInt(sever_num.val())-1) | |||
| @@ -368,10 +375,10 @@ | |||
| function Add_parameter(i){ | |||
| value = '<div class="two fields width85" id= "para'+ i +'">' + | |||
| '<div class="field">' + | |||
| '<input type="text" name="shipping_first-name" placeholder={{.i18n.Tr "repo.modelarts.train_job.parameter_name"}}> ' + | |||
| '<input type="text" name="shipping_first-name" required placeholder={{.i18n.Tr "repo.modelarts.train_job.parameter_name"}}> ' + | |||
| '</div> ' + | |||
| '<div class="field"> ' + | |||
| '<input type="text" name="shipping_last-name" placeholder={{.i18n.Tr "repo.modelarts.train_job.parameter_value"}}>' + | |||
| '<input type="text" name="shipping_last-name" required placeholder={{.i18n.Tr "repo.modelarts.train_job.parameter_value"}}>' + | |||
| '</div>'+ | |||
| '<span>' + | |||
| '<i class="trash icon">' + | |||
| @@ -471,6 +478,55 @@ | |||
| $('.ui.parameter.modal') | |||
| .modal('hide'); | |||
| }) | |||
| $('select.dropdown') | |||
| .dropdown(); | |||
| $('.ui.form') | |||
| .form({ | |||
| on: 'blur', | |||
| inline:true, | |||
| fields: { | |||
| boot_file: { | |||
| identifier : 'boot_file', | |||
| rules: [ | |||
| { | |||
| type: 'regExp[/.+\.py$/g]', | |||
| prompt : '启动文件必须为.py结尾' | |||
| } | |||
| ] | |||
| }, | |||
| job_name:{ | |||
| identifier : 'job_name', | |||
| rules: [ | |||
| { | |||
| type: 'regExp[/^[a-zA-Z0-9-_]{1,36}$/]', | |||
| prompt : '只包含大小写字母、数字、_和-,最长36个字符。' | |||
| } | |||
| ] | |||
| }, | |||
| attachment:{ | |||
| identifier : 'attachment', | |||
| rules: [ | |||
| { | |||
| type: 'empty', | |||
| prompt : '选择一个数据集' | |||
| } | |||
| ] | |||
| }, | |||
| work_server_number: { | |||
| identifier : 'work_server_number', | |||
| rules: [ | |||
| { | |||
| type : 'integer[1..25]', | |||
| prompt : '计算节点需要在1-25之间,请您键入正确的值' | |||
| } | |||
| ] | |||
| } | |||
| }, | |||
| }) | |||
| function validate(){ | |||
| $('.ui.form') | |||
| @@ -487,6 +543,25 @@ | |||
| } | |||
| ] | |||
| }, | |||
| job_name:{ | |||
| identifier : 'job_name', | |||
| rules: [ | |||
| { | |||
| type: 'regExp[/^[a-zA-Z0-9-_]{1,36}$/]', | |||
| prompt : '只包含大小写字母、数字、_和-,最长36个字符。' | |||
| } | |||
| ] | |||
| }, | |||
| attachment:{ | |||
| identifier : 'attachment', | |||
| rules: [ | |||
| { | |||
| type: 'empty', | |||
| prompt : '选择一个数据集' | |||
| } | |||
| ] | |||
| }, | |||
| work_server_number: { | |||
| identifier : 'work_server_number', | |||
| rules: [ | |||