Reviewed-on: https://git.openi.org.cn/OpenI/aiforge/pulls/1142tags/v1.21.12.1
| @@ -1059,50 +1059,50 @@ RESULT_BACKEND = redis://localhost:6379 | |||||
| [cloudbrain] | [cloudbrain] | ||||
| USERNAME = | USERNAME = | ||||
| PASSWORD = | PASSWORD = | ||||
| REST_SERVER_HOST = http://192.168.202.73 | |||||
| JOB_PATH = /datasets/minio/data/opendata/jobs/ | |||||
| DEBUG_SERVER_HOST = http://192.168.202.73/ | |||||
| REST_SERVER_HOST = | |||||
| JOB_PATH = | |||||
| DEBUG_SERVER_HOST = | |||||
| ; cloudbrain visit opendata | ; cloudbrain visit opendata | ||||
| USER = cW4cMtH24eoWPE7X | |||||
| PWD = 4BPmgvK2hb2Eywwyp4YZRY4B7yQf4DA.C | |||||
| GPU_TYPE_DEFAULT = openidebug | |||||
| GPU_TYPES = {"gpu_type":[{"id":1,"queue":"openidebug","value":"T4"},{"id":2,"queue":"openidgx","value":"V100"}]} | |||||
| USER = | |||||
| PWD = | |||||
| GPU_TYPE_DEFAULT = | |||||
| GPU_TYPES = | |||||
| [benchmark] | [benchmark] | ||||
| ENABLED = true | |||||
| BENCHMARKCODE = https://yangzhx:justfortest123@git.openi.org.cn/yangzhx/detection_benchmark_script.git | |||||
| HOST = http://192.168.202.90:3366/ | |||||
| ENABLED = | |||||
| BENCHMARKCODE = | |||||
| HOST = | |||||
| [snn4imagenet] | [snn4imagenet] | ||||
| ENABLED = true | |||||
| SNN4IMAGENETCODE = https://yult:eh2Ten4iLYjFkbj@git.openi.org.cn/ylt/snn4imagenet.git | |||||
| HOST = http://192.168.202.90:3366/ | |||||
| ENABLED = | |||||
| SNN4IMAGENETCODE = | |||||
| HOST = | |||||
| [decompress] | [decompress] | ||||
| HOST = http://192.168.207.34:39987 | |||||
| USER = cW4cMtH24eoWPE7X | |||||
| PASSWORD = 4BPmgvK2hb2Eywwyp4YZRY4B7yQf4DAC | |||||
| HOST = | |||||
| USER = | |||||
| PASSWORD = | |||||
| [blockchain] | [blockchain] | ||||
| HOST = http://192.168.207.84:3002/ | |||||
| COMMIT_VALID_DATE = 2021-01-15 | |||||
| HOST = | |||||
| COMMIT_VALID_DATE = | |||||
| [obs] | [obs] | ||||
| ENDPOINT = https://obs.cn-south-222.ai.pcl.cn | |||||
| ACCESS_KEY_ID = FDP3LRMHLB9S77VWEHE3 | |||||
| SECRET_ACCESS_KEY = LyM82Wk80pgjhs2z7AdDcsdpCWhbsJtSzQ7hkESN | |||||
| BUCKET = testopendata | |||||
| LOCATION = cn-south-222 | |||||
| BASE_PATH = attachment/ | |||||
| ENDPOINT = | |||||
| ACCESS_KEY_ID = | |||||
| SECRET_ACCESS_KEY = | |||||
| BUCKET = | |||||
| LOCATION = | |||||
| BASE_PATH = | |||||
| [modelarts] | [modelarts] | ||||
| ORGANIZATION = modelarts | |||||
| ENDPOINT = https://modelarts.cn-south-222.ai.pcl.cn | |||||
| PROJECT_ID = edfccf24aace4e17a56da6bcbb55a5aa | |||||
| PROJECT_NAME = cn-south-222_test | |||||
| USERNAME = test1 | |||||
| PASSWORD = Qizhi@test. | |||||
| DOMAIN = cn-south-222 | |||||
| ORGANIZATION = | |||||
| ENDPOINT = | |||||
| PROJECT_ID = | |||||
| PROJECT_NAME = | |||||
| USERNAME = | |||||
| PASSWORD = | |||||
| DOMAIN = | |||||
| [radar_map] | [radar_map] | ||||
| impact=0.3 | impact=0.3 | ||||
| @@ -0,0 +1,202 @@ | |||||
| package models | |||||
| import ( | |||||
| "fmt" | |||||
| "code.gitea.io/gitea/modules/log" | |||||
| "code.gitea.io/gitea/modules/setting" | |||||
| "code.gitea.io/gitea/modules/timeutil" | |||||
| "xorm.io/builder" | |||||
| "xorm.io/xorm" | |||||
| ) | |||||
| type AiModelManage struct { | |||||
| ID string `xorm:"pk"` | |||||
| Name string `xorm:"INDEX NOT NULL"` | |||||
| Version string `xorm:"NOT NULL"` | |||||
| VersionCount int `xorm:"NOT NULL DEFAULT 0"` | |||||
| New int `xorm:"NOT NULL"` | |||||
| Type int `xorm:"NOT NULL"` | |||||
| Size int64 `xorm:"NOT NULL"` | |||||
| Description string `xorm:"varchar(2000)"` | |||||
| Label string `xorm:"varchar(1000)"` | |||||
| Path string `xorm:"varchar(400) NOT NULL"` | |||||
| DownloadCount int `xorm:"NOT NULL DEFAULT 0"` | |||||
| Engine int64 `xorm:"NOT NULL DEFAULT 0"` | |||||
| Status int `xorm:"NOT NULL DEFAULT 0"` | |||||
| Accuracy string `xorm:"varchar(1000)"` | |||||
| AttachmentId string `xorm:"NULL"` | |||||
| RepoId int64 `xorm:"INDEX NULL"` | |||||
| CodeBranch string `xorm:"varchar(400) NULL"` | |||||
| CodeCommitID string `xorm:"NULL"` | |||||
| UserId int64 `xorm:"NOT NULL"` | |||||
| UserName string | |||||
| UserRelAvatarLink string | |||||
| TrainTaskInfo string `xorm:"text NULL"` | |||||
| CreatedUnix timeutil.TimeStamp `xorm:"created"` | |||||
| UpdatedUnix timeutil.TimeStamp `xorm:"updated"` | |||||
| IsCanOper bool | |||||
| } | |||||
| type AiModelQueryOptions struct { | |||||
| ListOptions | |||||
| RepoID int64 // include all repos if empty | |||||
| UserID int64 | |||||
| ModelID string | |||||
| SortType string | |||||
| New int | |||||
| // JobStatus CloudbrainStatus | |||||
| Type int | |||||
| } | |||||
| func SaveModelToDb(model *AiModelManage) error { | |||||
| sess := x.NewSession() | |||||
| defer sess.Close() | |||||
| re, err := sess.Insert(model) | |||||
| if err != nil { | |||||
| log.Info("insert error." + err.Error()) | |||||
| return err | |||||
| } | |||||
| log.Info("success to save db.re=" + fmt.Sprint((re))) | |||||
| return nil | |||||
| } | |||||
| func QueryModelById(id string) (*AiModelManage, error) { | |||||
| sess := x.NewSession() | |||||
| defer sess.Close() | |||||
| sess.Select("*").Table("ai_model_manage"). | |||||
| Where("id='" + id + "'") | |||||
| aiModelManageList := make([]*AiModelManage, 0) | |||||
| err := sess.Find(&aiModelManageList) | |||||
| if err == nil { | |||||
| if len(aiModelManageList) == 1 { | |||||
| return aiModelManageList[0], nil | |||||
| } | |||||
| } | |||||
| return nil, err | |||||
| } | |||||
| func DeleteModelById(id string) error { | |||||
| sess := x.NewSession() | |||||
| defer sess.Close() | |||||
| re, err := sess.Delete(&AiModelManage{ | |||||
| ID: id, | |||||
| }) | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| log.Info("success to delete from db.re=" + fmt.Sprint((re))) | |||||
| return nil | |||||
| } | |||||
| func ModifyModelDescription(id string, description string) error { | |||||
| var sess *xorm.Session | |||||
| sess = x.ID(id) | |||||
| defer sess.Close() | |||||
| re, err := sess.Cols("description").Update(&AiModelManage{ | |||||
| Description: description, | |||||
| }) | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| log.Info("success to update description from db.re=" + fmt.Sprint((re))) | |||||
| return nil | |||||
| } | |||||
| func ModifyModelNewProperty(id string, new int, versioncount int) error { | |||||
| var sess *xorm.Session | |||||
| sess = x.ID(id) | |||||
| defer sess.Close() | |||||
| re, err := sess.Cols("new", "version_count").Update(&AiModelManage{ | |||||
| New: new, | |||||
| VersionCount: versioncount, | |||||
| }) | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| log.Info("success to update new property from db.re=" + fmt.Sprint((re))) | |||||
| return nil | |||||
| } | |||||
| func ModifyModelDownloadCount(id string) error { | |||||
| sess := x.NewSession() | |||||
| defer sess.Close() | |||||
| if _, err := sess.Exec("UPDATE `ai_model_manage` SET download_count = download_count + 1 WHERE id = ?", id); err != nil { | |||||
| return err | |||||
| } | |||||
| return nil | |||||
| } | |||||
| func QueryModelByName(name string, repoId int64) []*AiModelManage { | |||||
| sess := x.NewSession() | |||||
| defer sess.Close() | |||||
| sess.Select("*").Table("ai_model_manage"). | |||||
| Where("name='" + name + "' and repo_id=" + fmt.Sprint(repoId)).OrderBy("created_unix desc") | |||||
| aiModelManageList := make([]*AiModelManage, 0) | |||||
| sess.Find(&aiModelManageList) | |||||
| return aiModelManageList | |||||
| } | |||||
| func QueryModel(opts *AiModelQueryOptions) ([]*AiModelManage, int64, error) { | |||||
| sess := x.NewSession() | |||||
| defer sess.Close() | |||||
| var cond = builder.NewCond() | |||||
| if opts.RepoID > 0 { | |||||
| cond = cond.And( | |||||
| builder.Eq{"ai_model_manage.repo_id": opts.RepoID}, | |||||
| ) | |||||
| } | |||||
| if opts.UserID > 0 { | |||||
| cond = cond.And( | |||||
| builder.Eq{"ai_model_manage.user_id": opts.UserID}, | |||||
| ) | |||||
| } | |||||
| if opts.New >= 0 { | |||||
| cond = cond.And( | |||||
| builder.Eq{"ai_model_manage.new": opts.New}, | |||||
| ) | |||||
| } | |||||
| if len(opts.ModelID) > 0 { | |||||
| cond = cond.And( | |||||
| builder.Eq{"ai_model_manage.id": opts.ModelID}, | |||||
| ) | |||||
| } | |||||
| if (opts.Type) >= 0 { | |||||
| cond = cond.And( | |||||
| builder.Eq{"ai_model_manage.type": opts.Type}, | |||||
| ) | |||||
| } | |||||
| count, err := sess.Where(cond).Count(new(AiModelManage)) | |||||
| if err != nil { | |||||
| return nil, 0, fmt.Errorf("Count: %v", err) | |||||
| } | |||||
| if opts.Page >= 0 && opts.PageSize > 0 { | |||||
| var start int | |||||
| if opts.Page == 0 { | |||||
| start = 0 | |||||
| } else { | |||||
| start = (opts.Page - 1) * opts.PageSize | |||||
| } | |||||
| sess.Limit(opts.PageSize, start) | |||||
| } | |||||
| sess.OrderBy("ai_model_manage.created_unix DESC") | |||||
| aiModelManages := make([]*AiModelManage, 0, setting.UI.IssuePagingNum) | |||||
| if err := sess.Table("ai_model_manage").Where(cond). | |||||
| Find(&aiModelManages); err != nil { | |||||
| return nil, 0, fmt.Errorf("Find: %v", err) | |||||
| } | |||||
| return aiModelManages, count, nil | |||||
| } | |||||
| @@ -91,6 +91,7 @@ type Cloudbrain struct { | |||||
| DeletedAt time.Time `xorm:"deleted"` | DeletedAt time.Time `xorm:"deleted"` | ||||
| CanDebug bool `xorm:"-"` | CanDebug bool `xorm:"-"` | ||||
| CanDel bool `xorm:"-"` | CanDel bool `xorm:"-"` | ||||
| CanModify bool `xorm:"-"` | |||||
| Type int | Type int | ||||
| VersionID int64 //版本id | VersionID int64 //版本id | ||||
| @@ -928,6 +929,58 @@ func Cloudbrains(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, error) { | |||||
| return cloudbrains, count, nil | return cloudbrains, count, nil | ||||
| } | } | ||||
| func QueryModelTrainJobVersionList(jobId string) ([]*CloudbrainInfo, int, error) { | |||||
| sess := x.NewSession() | |||||
| defer sess.Close() | |||||
| var cond = builder.NewCond() | |||||
| cond = cond.And( | |||||
| builder.Eq{"cloudbrain.job_id": jobId}, | |||||
| ) | |||||
| cond = cond.And( | |||||
| builder.Eq{"cloudbrain.Status": "COMPLETED"}, | |||||
| ) | |||||
| sess.OrderBy("cloudbrain.created_unix DESC") | |||||
| cloudbrains := make([]*CloudbrainInfo, 0) | |||||
| if err := sess.Table(&Cloudbrain{}).Where(cond). | |||||
| Find(&cloudbrains); err != nil { | |||||
| return nil, 0, fmt.Errorf("Find: %v", err) | |||||
| } | |||||
| return cloudbrains, int(len(cloudbrains)), nil | |||||
| } | |||||
| func QueryModelTrainJobList(repoId int64) ([]*CloudbrainInfo, int, error) { | |||||
| sess := x.NewSession() | |||||
| defer sess.Close() | |||||
| var cond = builder.NewCond() | |||||
| cond = cond.And( | |||||
| builder.Eq{"repo_id": repoId}, | |||||
| ) | |||||
| cond = cond.And( | |||||
| builder.Eq{"Status": "COMPLETED"}, | |||||
| ) | |||||
| cloudbrains := make([]*CloudbrainInfo, 0) | |||||
| if err := sess.Select("job_id,job_name").Table(&Cloudbrain{}).Where(cond).OrderBy("created_unix DESC"). | |||||
| Find(&cloudbrains); err != nil { | |||||
| return nil, 0, fmt.Errorf("Find: %v", err) | |||||
| } | |||||
| keys := make(map[string]string) | |||||
| uniqueElements := make([]*CloudbrainInfo, 0) | |||||
| for _, entry := range cloudbrains { | |||||
| if _, value := keys[entry.JobID]; !value { | |||||
| keys[entry.JobID] = entry.JobName | |||||
| uniqueElements = append(uniqueElements, entry) | |||||
| } | |||||
| } | |||||
| return uniqueElements, int(len(uniqueElements)), nil | |||||
| } | |||||
| func CloudbrainsVersionList(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int, error) { | func CloudbrainsVersionList(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int, error) { | ||||
| sess := x.NewSession() | sess := x.NewSession() | ||||
| defer sess.Close() | defer sess.Close() | ||||
| @@ -1032,13 +1085,13 @@ func GetCloudbrainByJobIDAndIsLatestVersion(jobID string, isLatestVersion string | |||||
| func GetCloudbrainsNeededStopByUserID(userID int64) ([]*Cloudbrain, error) { | func GetCloudbrainsNeededStopByUserID(userID int64) ([]*Cloudbrain, error) { | ||||
| cloudBrains := make([]*Cloudbrain, 0) | cloudBrains := make([]*Cloudbrain, 0) | ||||
| err := x.Cols("job_id", "status", "type").Where("user_id=? AND status !=?", userID, string(JobStopped)).Find(&cloudBrains) | |||||
| err := x.Cols("job_id", "status", "type", "job_type", "version_id").Where("user_id=? AND status !=?", userID, string(JobStopped)).Find(&cloudBrains) | |||||
| return cloudBrains, err | return cloudBrains, err | ||||
| } | } | ||||
| func GetCloudbrainsNeededStopByRepoID(repoID int64) ([]*Cloudbrain, error) { | func GetCloudbrainsNeededStopByRepoID(repoID int64) ([]*Cloudbrain, error) { | ||||
| cloudBrains := make([]*Cloudbrain, 0) | cloudBrains := make([]*Cloudbrain, 0) | ||||
| err := x.Cols("job_id", "status", "type").Where("repo_id=? AND status !=?", repoID, string(JobStopped)).Find(&cloudBrains) | |||||
| err := x.Cols("job_id", "status", "type", "job_type", "version_id").Where("repo_id=? AND status !=?", repoID, string(JobStopped)).Find(&cloudBrains) | |||||
| return cloudBrains, err | return cloudBrains, err | ||||
| } | } | ||||
| @@ -1065,9 +1118,7 @@ func UpdateJob(job *Cloudbrain) error { | |||||
| } | } | ||||
| func updateJob(e Engine, job *Cloudbrain) error { | func updateJob(e Engine, job *Cloudbrain) error { | ||||
| var sess *xorm.Session | |||||
| sess = e.Where("job_id = ?", job.JobID) | |||||
| _, err := sess.Cols("status", "container_id", "container_ip").Update(job) | |||||
| _, err := e.ID(job.ID).AllCols().Update(job) | |||||
| return err | return err | ||||
| } | } | ||||
| @@ -93,6 +93,7 @@ type SearchDatasetOptions struct { | |||||
| IncludePublic bool | IncludePublic bool | ||||
| ListOptions | ListOptions | ||||
| SearchOrderBy | SearchOrderBy | ||||
| IsOwner bool | |||||
| } | } | ||||
| func CreateDataset(dataset *Dataset) (err error) { | func CreateDataset(dataset *Dataset) (err error) { | ||||
| @@ -150,6 +151,9 @@ func SearchDatasetCondition(opts *SearchDatasetOptions) builder.Cond { | |||||
| } | } | ||||
| } else if opts.OwnerID > 0 { | } else if opts.OwnerID > 0 { | ||||
| cond = cond.And(builder.Eq{"repository.owner_id": opts.OwnerID}) | cond = cond.And(builder.Eq{"repository.owner_id": opts.OwnerID}) | ||||
| if !opts.IsOwner { | |||||
| cond = cond.And(builder.Eq{"dataset.status": DatasetStatusPublic}) | |||||
| } | |||||
| } | } | ||||
| return cond | return cond | ||||
| @@ -133,6 +133,7 @@ func init() { | |||||
| new(FileChunk), | new(FileChunk), | ||||
| new(BlockChain), | new(BlockChain), | ||||
| new(RecommendOrg), | new(RecommendOrg), | ||||
| new(AiModelManage), | |||||
| ) | ) | ||||
| tablesStatistic = append(tablesStatistic, | tablesStatistic = append(tablesStatistic, | ||||
| @@ -11,6 +11,7 @@ import ( | |||||
| "errors" | "errors" | ||||
| "fmt" | "fmt" | ||||
| "html/template" | "html/template" | ||||
| "xorm.io/xorm" | |||||
| "code.gitea.io/gitea/modules/blockchain" | "code.gitea.io/gitea/modules/blockchain" | ||||
| @@ -648,53 +649,41 @@ func (repo *Repository) GetAssignees() (_ []*User, err error) { | |||||
| return repo.getAssignees(x) | return repo.getAssignees(x) | ||||
| } | } | ||||
| func (repo *Repository) getReviewersPrivate(e Engine, doerID, posterID int64) (users []*User, err error) { | |||||
| users = make([]*User, 0, 20) | |||||
| if err = e. | |||||
| SQL("SELECT * FROM `user` WHERE id in (SELECT user_id FROM `access` WHERE repo_id = ? AND mode >= ? AND user_id NOT IN ( ?, ?)) ORDER BY name", | |||||
| repo.ID, AccessModeRead, | |||||
| doerID, posterID). | |||||
| Find(&users); err != nil { | |||||
| return nil, err | |||||
| } | |||||
| return users, nil | |||||
| } | |||||
| func (repo *Repository) getReviewersPublic(e Engine, doerID, posterID int64) (_ []*User, err error) { | |||||
| users := make([]*User, 0) | |||||
| const SQLCmd = "SELECT * FROM `user` WHERE id IN ( " + | |||||
| "SELECT user_id FROM `access` WHERE repo_id = ? AND mode >= ? AND user_id NOT IN ( ?, ?) " + | |||||
| "UNION " + | |||||
| "SELECT user_id FROM `watch` WHERE repo_id = ? AND user_id NOT IN ( ?, ?) AND mode IN (?, ?) " + | |||||
| ") ORDER BY name" | |||||
| if err = e. | |||||
| SQL(SQLCmd, | |||||
| repo.ID, AccessModeRead, doerID, posterID, | |||||
| repo.ID, doerID, posterID, RepoWatchModeNormal, RepoWatchModeAuto). | |||||
| Find(&users); err != nil { | |||||
| return nil, err | |||||
| } | |||||
| return users, nil | |||||
| } | |||||
| func (repo *Repository) getReviewers(e Engine, doerID, posterID int64) (users []*User, err error) { | func (repo *Repository) getReviewers(e Engine, doerID, posterID int64) (users []*User, err error) { | ||||
| if err = repo.getOwner(e); err != nil { | if err = repo.getOwner(e); err != nil { | ||||
| return nil, err | return nil, err | ||||
| } | } | ||||
| if repo.IsPrivate || | |||||
| (repo.Owner.IsOrganization() && repo.Owner.Visibility == api.VisibleTypePrivate) { | |||||
| users, err = repo.getReviewersPrivate(x, doerID, posterID) | |||||
| if repo.Owner.IsOrganization() { | |||||
| const SQLCmd = "SELECT * FROM `user` WHERE id IN (" + | |||||
| "SELECT DISTINCT(t3.user_id) FROM ( " + | |||||
| "SELECT user_id FROM `access` WHERE repo_id = ? AND mode >= ?" + | |||||
| "UNION select t2.uid as user_id from team t1 left join team_user t2 on t1.id = t2.team_id where t1.org_id = ? and t1.authorize = 4) t3)" + | |||||
| " AND id NOT IN ( ?, ?) ORDER BY name " | |||||
| if err = e. | |||||
| SQL(SQLCmd, | |||||
| repo.ID, AccessModeWrite, repo.ID, doerID, posterID). | |||||
| Find(&users); err != nil { | |||||
| return nil, err | |||||
| } | |||||
| } else { | } else { | ||||
| users, err = repo.getReviewersPublic(x, doerID, posterID) | |||||
| const SQLCmd = "SELECT * FROM `user` WHERE id IN ( " + | |||||
| "SELECT DISTINCT(t3.user_id) FROM ( " + | |||||
| "SELECT user_id FROM `access` WHERE repo_id = ? AND mode >= ? " + | |||||
| " UNION" + | |||||
| " SELECT owner_id as user_id FROM `repository` WHERE id = ?) t3)" + | |||||
| " AND id NOT IN ( ?, ?) ORDER BY name " | |||||
| if err = e. | |||||
| SQL(SQLCmd, | |||||
| repo.ID, AccessModeWrite, repo.ID, doerID, posterID). | |||||
| Find(&users); err != nil { | |||||
| return nil, err | |||||
| } | |||||
| } | } | ||||
| return | |||||
| return users, nil | |||||
| } | } | ||||
| // GetReviewers get all users can be requested to review | // GetReviewers get all users can be requested to review | ||||
| @@ -1118,6 +1107,12 @@ func CreateRepository(ctx DBContext, doer, u *User, repo *Repository) (err error | |||||
| Type: tp, | Type: tp, | ||||
| Config: &BlockChainConfig{EnableBlockChain: true}, | Config: &BlockChainConfig{EnableBlockChain: true}, | ||||
| }) | }) | ||||
| } else if tp == UnitTypeModelManage { | |||||
| units = append(units, RepoUnit{ | |||||
| RepoID: repo.ID, | |||||
| Type: tp, | |||||
| Config: &ModelManageConfig{EnableModelManage: true}, | |||||
| }) | |||||
| } else { | } else { | ||||
| units = append(units, RepoUnit{ | units = append(units, RepoUnit{ | ||||
| RepoID: repo.ID, | RepoID: repo.ID, | ||||
| @@ -1630,6 +1625,9 @@ func DeleteRepository(doer *User, uid, repoID int64) error { | |||||
| releaseAttachments = append(releaseAttachments, attachments[i].RelativePath()) | releaseAttachments = append(releaseAttachments, attachments[i].RelativePath()) | ||||
| } | } | ||||
| // Delete dataset attachment record and remove related files | |||||
| deleteDatasetAttachmentByRepoId(sess, repoID) | |||||
| if err = deleteBeans(sess, | if err = deleteBeans(sess, | ||||
| &Access{RepoID: repo.ID}, | &Access{RepoID: repo.ID}, | ||||
| &Action{RepoID: repo.ID}, | &Action{RepoID: repo.ID}, | ||||
| @@ -1815,6 +1813,20 @@ func DeleteRepository(doer *User, uid, repoID int64) error { | |||||
| return nil | return nil | ||||
| } | } | ||||
| func deleteDatasetAttachmentByRepoId(sess *xorm.Session, repoId int64) error { | |||||
| attachments := make([]*Attachment, 0) | |||||
| if err := sess.Join("INNER", "dataset", "dataset.id = attachment.dataset_id"). | |||||
| Where("dataset.repo_id = ?", repoId). | |||||
| Find(&attachments); err != nil { | |||||
| return err | |||||
| } | |||||
| if len(attachments) == 0 { | |||||
| return nil | |||||
| } | |||||
| _, err := DeleteAttachments(attachments, true) | |||||
| return err | |||||
| } | |||||
| // GetRepositoryByOwnerAndName returns the repository by given ownername and reponame. | // GetRepositoryByOwnerAndName returns the repository by given ownername and reponame. | ||||
| func GetRepositoryByOwnerAndName(ownerName, repoName string) (*Repository, error) { | func GetRepositoryByOwnerAndName(ownerName, repoName string) (*Repository, error) { | ||||
| return getRepositoryByOwnerAndName(x, ownerName, repoName) | return getRepositoryByOwnerAndName(x, ownerName, repoName) | ||||
| @@ -131,6 +131,20 @@ type CloudBrainConfig struct { | |||||
| EnableCloudBrain bool | EnableCloudBrain bool | ||||
| } | } | ||||
| type ModelManageConfig struct { | |||||
| EnableModelManage bool | |||||
| } | |||||
| // FromDB fills up a CloudBrainConfig from serialized format. | |||||
| func (cfg *ModelManageConfig) FromDB(bs []byte) error { | |||||
| return json.Unmarshal(bs, &cfg) | |||||
| } | |||||
| // ToDB exports a CloudBrainConfig to a serialized format. | |||||
| func (cfg *ModelManageConfig) ToDB() ([]byte, error) { | |||||
| return json.Marshal(cfg) | |||||
| } | |||||
| // FromDB fills up a CloudBrainConfig from serialized format. | // FromDB fills up a CloudBrainConfig from serialized format. | ||||
| func (cfg *CloudBrainConfig) FromDB(bs []byte) error { | func (cfg *CloudBrainConfig) FromDB(bs []byte) error { | ||||
| return json.Unmarshal(bs, &cfg) | return json.Unmarshal(bs, &cfg) | ||||
| @@ -176,6 +190,8 @@ func (r *RepoUnit) BeforeSet(colName string, val xorm.Cell) { | |||||
| r.Config = new(CloudBrainConfig) | r.Config = new(CloudBrainConfig) | ||||
| case UnitTypeBlockChain: | case UnitTypeBlockChain: | ||||
| r.Config = new(BlockChainConfig) | r.Config = new(BlockChainConfig) | ||||
| case UnitTypeModelManage: | |||||
| r.Config = new(ModelManageConfig) | |||||
| default: | default: | ||||
| panic("unrecognized repo unit type: " + com.ToStr(*val)) | panic("unrecognized repo unit type: " + com.ToStr(*val)) | ||||
| } | } | ||||
| @@ -27,6 +27,7 @@ const ( | |||||
| UnitTypeDatasets UnitType = 10 // 10 Dataset | UnitTypeDatasets UnitType = 10 // 10 Dataset | ||||
| UnitTypeCloudBrain UnitType = 11 // 11 CloudBrain | UnitTypeCloudBrain UnitType = 11 // 11 CloudBrain | ||||
| UnitTypeBlockChain UnitType = 12 // 12 BlockChain | UnitTypeBlockChain UnitType = 12 // 12 BlockChain | ||||
| UnitTypeModelManage UnitType = 13 // 13 ModelManage | |||||
| ) | ) | ||||
| // Value returns integer value for unit type | // Value returns integer value for unit type | ||||
| @@ -56,6 +57,8 @@ func (u UnitType) String() string { | |||||
| return "UnitTypeCloudBrain" | return "UnitTypeCloudBrain" | ||||
| case UnitTypeBlockChain: | case UnitTypeBlockChain: | ||||
| return "UnitTypeBlockChain" | return "UnitTypeBlockChain" | ||||
| case UnitTypeModelManage: | |||||
| return "UnitTypeModelManage" | |||||
| } | } | ||||
| return fmt.Sprintf("Unknown UnitType %d", u) | return fmt.Sprintf("Unknown UnitType %d", u) | ||||
| } | } | ||||
| @@ -80,6 +83,7 @@ var ( | |||||
| UnitTypeDatasets, | UnitTypeDatasets, | ||||
| UnitTypeCloudBrain, | UnitTypeCloudBrain, | ||||
| UnitTypeBlockChain, | UnitTypeBlockChain, | ||||
| UnitTypeModelManage, | |||||
| } | } | ||||
| // DefaultRepoUnits contains the default unit types | // DefaultRepoUnits contains the default unit types | ||||
| @@ -92,6 +96,7 @@ var ( | |||||
| UnitTypeDatasets, | UnitTypeDatasets, | ||||
| UnitTypeCloudBrain, | UnitTypeCloudBrain, | ||||
| UnitTypeBlockChain, | UnitTypeBlockChain, | ||||
| UnitTypeModelManage, | |||||
| } | } | ||||
| // NotAllowedDefaultRepoUnits contains units that can't be default | // NotAllowedDefaultRepoUnits contains units that can't be default | ||||
| @@ -281,6 +286,14 @@ var ( | |||||
| 7, | 7, | ||||
| } | } | ||||
| UnitModelManage = Unit{ | |||||
| UnitTypeModelManage, | |||||
| "repo.modelmanage", | |||||
| "/modelmanage", | |||||
| "repo.modelmanage.desc", | |||||
| 8, | |||||
| } | |||||
| // Units contains all the units | // Units contains all the units | ||||
| Units = map[UnitType]Unit{ | Units = map[UnitType]Unit{ | ||||
| UnitTypeCode: UnitCode, | UnitTypeCode: UnitCode, | ||||
| @@ -293,6 +306,7 @@ var ( | |||||
| UnitTypeDatasets: UnitDataset, | UnitTypeDatasets: UnitDataset, | ||||
| UnitTypeCloudBrain: UnitCloudBrain, | UnitTypeCloudBrain: UnitCloudBrain, | ||||
| UnitTypeBlockChain: UnitBlockChain, | UnitTypeBlockChain: UnitBlockChain, | ||||
| UnitTypeModelManage: UnitModelManage, | |||||
| } | } | ||||
| ) | ) | ||||
| @@ -145,6 +145,7 @@ type User struct { | |||||
| AllowImportLocal bool // Allow migrate repository by local path | AllowImportLocal bool // Allow migrate repository by local path | ||||
| AllowCreateOrganization bool `xorm:"DEFAULT true"` | AllowCreateOrganization bool `xorm:"DEFAULT true"` | ||||
| ProhibitLogin bool `xorm:"NOT NULL DEFAULT false"` | ProhibitLogin bool `xorm:"NOT NULL DEFAULT false"` | ||||
| IsOperator bool `xorm:"NOT NULL DEFAULT false"` //运营人员 | |||||
| // Avatar | // Avatar | ||||
| Avatar string `xorm:"VARCHAR(2048) NOT NULL"` | Avatar string `xorm:"VARCHAR(2048) NOT NULL"` | ||||
| @@ -928,8 +929,17 @@ var ( | |||||
| "template", | "template", | ||||
| "user", | "user", | ||||
| "vendor", | "vendor", | ||||
| } | |||||
| reservedUserPatterns = []string{"*.keys", "*.gpg"} | |||||
| "dashboard", | |||||
| "operation", | |||||
| "blockchain", | |||||
| "avatar", | |||||
| "swagger.v1.json", | |||||
| "secure", | |||||
| "serviceworker.js", | |||||
| "self", | |||||
| "repo-avatars", | |||||
| } | |||||
| reservedUserPatterns = []string{"*.keys", "*.gpg", "*.png"} | |||||
| ) | ) | ||||
| // isUsableName checks if name is reserved or pattern of name is not allowed | // isUsableName checks if name is reserved or pattern of name is not allowed | ||||
| @@ -1551,11 +1561,11 @@ func GetUserByActivateEmail(email string) (*User, error) { | |||||
| if err := ctx.e.Join("INNER", "email_address", "email_address.uid = \"user\".id"). | if err := ctx.e.Join("INNER", "email_address", "email_address.uid = \"user\".id"). | ||||
| Where("email_address.email= ?", email). | Where("email_address.email= ?", email). | ||||
| Find(&users); err != nil { | Find(&users); err != nil { | ||||
| return nil,err | |||||
| return nil, err | |||||
| } | } | ||||
| if len(users) >= 1 { | if len(users) >= 1 { | ||||
| return &users[0],nil | |||||
| }else { | |||||
| return &users[0], nil | |||||
| } else { | |||||
| // Finally, if email address is the protected email address:用户邮件地址设置为隐藏电子邮件地址 | // Finally, if email address is the protected email address:用户邮件地址设置为隐藏电子邮件地址 | ||||
| if strings.HasSuffix(email, fmt.Sprintf("@%s", setting.Service.NoReplyAddress)) { | if strings.HasSuffix(email, fmt.Sprintf("@%s", setting.Service.NoReplyAddress)) { | ||||
| username := strings.TrimSuffix(email, fmt.Sprintf("@%s", setting.Service.NoReplyAddress)) | username := strings.TrimSuffix(email, fmt.Sprintf("@%s", setting.Service.NoReplyAddress)) | ||||
| @@ -1571,6 +1581,7 @@ func GetUserByActivateEmail(email string) (*User, error) { | |||||
| return nil, errors.New("cannot find user by email") | return nil, errors.New("cannot find user by email") | ||||
| } | } | ||||
| } | } | ||||
| // GetUserByEmail returns the user object by given e-mail if exists. | // GetUserByEmail returns the user object by given e-mail if exists. | ||||
| func GetUserByEmail(email string) (*User, error) { | func GetUserByEmail(email string) (*User, error) { | ||||
| return GetUserByEmailContext(DefaultDBContext(), email) | return GetUserByEmailContext(DefaultDBContext(), email) | ||||
| @@ -9,6 +9,9 @@ import ( | |||||
| "reflect" | "reflect" | ||||
| "strings" | "strings" | ||||
| "code.gitea.io/gitea/modules/base" | |||||
| "code.gitea.io/gitea/modules/setting" | |||||
| "code.gitea.io/gitea/models" | "code.gitea.io/gitea/models" | ||||
| "code.gitea.io/gitea/modules/auth/sso" | "code.gitea.io/gitea/modules/auth/sso" | ||||
| "code.gitea.io/gitea/modules/validation" | "code.gitea.io/gitea/modules/validation" | ||||
| @@ -31,6 +34,8 @@ func SignedInUser(ctx *macaron.Context, sess session.Store) (*models.User, bool) | |||||
| return nil, false | return nil, false | ||||
| } | } | ||||
| checkAutoLogin(ctx, sess) | |||||
| // Try to sign in with each of the enabled plugins | // Try to sign in with each of the enabled plugins | ||||
| for _, ssoMethod := range sso.Methods() { | for _, ssoMethod := range sso.Methods() { | ||||
| if !ssoMethod.IsEnabled() { | if !ssoMethod.IsEnabled() { | ||||
| @@ -46,6 +51,23 @@ func SignedInUser(ctx *macaron.Context, sess session.Store) (*models.User, bool) | |||||
| return nil, false | return nil, false | ||||
| } | } | ||||
| func checkAutoLogin(ctx *macaron.Context, sess session.Store) { | |||||
| uid := sess.Get("uid") | |||||
| if uid == nil { | |||||
| uname := ctx.GetCookie(setting.CookieUserName) | |||||
| u, err := models.GetUserByName(uname) | |||||
| if err == nil { | |||||
| if val, ok := ctx.GetSuperSecureCookie( | |||||
| base.EncodeMD5(u.Rands+u.Passwd), setting.CookieRememberName); ok && val == u.Name { | |||||
| sess.Set("uid", u.ID) | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| // Form form binding interface | // Form form binding interface | ||||
| type Form interface { | type Form interface { | ||||
| binding.Validator | binding.Validator | ||||
| @@ -122,6 +122,7 @@ type RepoSettingForm struct { | |||||
| // Advanced settings | // Advanced settings | ||||
| EnableDataset bool | EnableDataset bool | ||||
| EnableCloudBrain bool | EnableCloudBrain bool | ||||
| EnableModelManager bool | |||||
| EnableWiki bool | EnableWiki bool | ||||
| EnableExternalWiki bool | EnableExternalWiki bool | ||||
| ExternalWikiURL string | ExternalWikiURL string | ||||
| @@ -1,8 +1,10 @@ | |||||
| package cloudbrain | package cloudbrain | ||||
| import ( | import ( | ||||
| "code.gitea.io/gitea/modules/setting" | |||||
| "errors" | "errors" | ||||
| "strconv" | |||||
| "code.gitea.io/gitea/modules/setting" | |||||
| "code.gitea.io/gitea/models" | "code.gitea.io/gitea/models" | ||||
| "code.gitea.io/gitea/modules/context" | "code.gitea.io/gitea/modules/context" | ||||
| @@ -16,7 +18,7 @@ const ( | |||||
| ModelMountPath = "/model" | ModelMountPath = "/model" | ||||
| BenchMarkMountPath = "/benchmark" | BenchMarkMountPath = "/benchmark" | ||||
| Snn4imagenetMountPath = "/snn4imagenet" | Snn4imagenetMountPath = "/snn4imagenet" | ||||
| BrainScoreMountPath = "/brainscore" | |||||
| BrainScoreMountPath = "/brainscore" | |||||
| TaskInfoName = "/taskInfo" | TaskInfoName = "/taskInfo" | ||||
| SubTaskName = "task1" | SubTaskName = "task1" | ||||
| @@ -28,6 +30,75 @@ var ( | |||||
| ResourceSpecs *models.ResourceSpecs | ResourceSpecs *models.ResourceSpecs | ||||
| ) | ) | ||||
| func isAdminOrOwnerOrJobCreater(ctx *context.Context, job *models.Cloudbrain, err error) bool { | |||||
| if !ctx.IsSigned { | |||||
| return false | |||||
| } | |||||
| log.Info("is repo owner:" + strconv.FormatBool(ctx.IsUserRepoOwner())) | |||||
| log.Info("is user admin:" + strconv.FormatBool(ctx.IsUserSiteAdmin())) | |||||
| if err != nil { | |||||
| return ctx.IsUserRepoOwner() || ctx.IsUserSiteAdmin() | |||||
| } else { | |||||
| log.Info("is job creator:" + strconv.FormatBool(ctx.User.ID == job.UserID)) | |||||
| return ctx.IsUserRepoOwner() || ctx.IsUserSiteAdmin() || ctx.User.ID == job.UserID | |||||
| } | |||||
| } | |||||
| func CanDeleteJob(ctx *context.Context, job *models.Cloudbrain) bool { | |||||
| return isAdminOrOwnerOrJobCreater(ctx, job, nil) | |||||
| } | |||||
| func CanCreateOrDebugJob(ctx *context.Context) bool { | |||||
| if !ctx.IsSigned { | |||||
| return false | |||||
| } | |||||
| return ctx.Repo.CanWrite(models.UnitTypeCloudBrain) | |||||
| } | |||||
| func CanModifyJob(ctx *context.Context, job *models.Cloudbrain) bool { | |||||
| return isAdminOrJobCreater(ctx, job, nil) | |||||
| } | |||||
| func isAdminOrJobCreater(ctx *context.Context, job *models.Cloudbrain, err error) bool { | |||||
| if !ctx.IsSigned { | |||||
| return false | |||||
| } | |||||
| if err != nil { | |||||
| return ctx.IsUserSiteAdmin() | |||||
| } else { | |||||
| return ctx.IsUserSiteAdmin() || ctx.User.ID == job.UserID | |||||
| } | |||||
| } | |||||
| func AdminOrOwnerOrJobCreaterRight(ctx *context.Context) { | |||||
| var jobID = ctx.Params(":jobid") | |||||
| job, err := models.GetCloudbrainByJobID(jobID) | |||||
| if !isAdminOrOwnerOrJobCreater(ctx, job, err) { | |||||
| ctx.NotFound(ctx.Req.URL.RequestURI(), nil) | |||||
| } | |||||
| } | |||||
| func AdminOrJobCreaterRight(ctx *context.Context) { | |||||
| var jobID = ctx.Params(":jobid") | |||||
| job, err := models.GetCloudbrainByJobID(jobID) | |||||
| if !isAdminOrJobCreater(ctx, job, err) { | |||||
| ctx.NotFound(ctx.Req.URL.RequestURI(), nil) | |||||
| } | |||||
| } | |||||
| func GenerateTask(ctx *context.Context, jobName, image, command, uuid, codePath, modelPath, benchmarkPath, snn4imagenetPath, brainScorePath, jobType, gpuQueue string, resourceSpecId int) error { | func GenerateTask(ctx *context.Context, jobName, image, command, uuid, codePath, modelPath, benchmarkPath, snn4imagenetPath, brainScorePath, jobType, gpuQueue string, resourceSpecId int) error { | ||||
| dataActualPath := setting.Attachment.Minio.RealPath + | dataActualPath := setting.Attachment.Minio.RealPath + | ||||
| setting.Attachment.Minio.Bucket + "/" + | setting.Attachment.Minio.Bucket + "/" + | ||||
| @@ -46,7 +117,7 @@ func GenerateTask(ctx *context.Context, jobName, image, command, uuid, codePath, | |||||
| log.Error("no such resourceSpecId(%d)", resourceSpecId, ctx.Data["MsgID"]) | log.Error("no such resourceSpecId(%d)", resourceSpecId, ctx.Data["MsgID"]) | ||||
| return errors.New("no such resourceSpec") | return errors.New("no such resourceSpec") | ||||
| } | } | ||||
| jobResult, err := CreateJob(jobName, models.CreateJobParams{ | jobResult, err := CreateJob(jobName, models.CreateJobParams{ | ||||
| JobName: jobName, | JobName: jobName, | ||||
| RetryCount: 1, | RetryCount: 1, | ||||
| @@ -131,8 +202,8 @@ func GenerateTask(ctx *context.Context, jobName, image, command, uuid, codePath, | |||||
| JobName: jobName, | JobName: jobName, | ||||
| SubTaskName: SubTaskName, | SubTaskName: SubTaskName, | ||||
| JobType: jobType, | JobType: jobType, | ||||
| Type: models.TypeCloudBrainOne, | |||||
| Uuid: uuid, | |||||
| Type: models.TypeCloudBrainOne, | |||||
| Uuid: uuid, | |||||
| }) | }) | ||||
| if err != nil { | if err != nil { | ||||
| @@ -145,8 +145,7 @@ func Toggle(options *ToggleOptions) macaron.Handler { | |||||
| } | } | ||||
| if options.OperationRequired { | if options.OperationRequired { | ||||
| //todo: add isOperator judgement | |||||
| if !ctx.User.IsAdmin { | |||||
| if !ctx.User.IsOperator { | |||||
| ctx.Error(403) | ctx.Error(403) | ||||
| return | return | ||||
| } | } | ||||
| @@ -310,6 +310,7 @@ func Contexter() macaron.Handler { | |||||
| ctx.Data["SignedUserID"] = ctx.User.ID | ctx.Data["SignedUserID"] = ctx.User.ID | ||||
| ctx.Data["SignedUserName"] = ctx.User.Name | ctx.Data["SignedUserName"] = ctx.User.Name | ||||
| ctx.Data["IsAdmin"] = ctx.User.IsAdmin | ctx.Data["IsAdmin"] = ctx.User.IsAdmin | ||||
| ctx.Data["IsOperator"] = ctx.User.IsOperator | |||||
| c.Data["SignedUserName"] = ctx.User.Name | c.Data["SignedUserName"] = ctx.User.Name | ||||
| } else { | } else { | ||||
| ctx.Data["SignedUserID"] = int64(0) | ctx.Data["SignedUserID"] = int64(0) | ||||
| @@ -821,5 +821,6 @@ func UnitTypes() macaron.Handler { | |||||
| ctx.Data["UnitTypeExternalWiki"] = models.UnitTypeExternalWiki | ctx.Data["UnitTypeExternalWiki"] = models.UnitTypeExternalWiki | ||||
| ctx.Data["UnitTypeExternalTracker"] = models.UnitTypeExternalTracker | ctx.Data["UnitTypeExternalTracker"] = models.UnitTypeExternalTracker | ||||
| ctx.Data["UnitTypeBlockChain"] = models.UnitTypeBlockChain | ctx.Data["UnitTypeBlockChain"] = models.UnitTypeBlockChain | ||||
| ctx.Data["UnitTypeModelManage"] = models.UnitTypeModelManage | |||||
| } | } | ||||
| } | } | ||||
| @@ -134,7 +134,7 @@ func registerHandleBlockChainUnSuccessRepos() { | |||||
| RegisterTaskFatal("handle_blockchain_unsuccess_repos", &BaseConfig{ | RegisterTaskFatal("handle_blockchain_unsuccess_repos", &BaseConfig{ | ||||
| Enabled: true, | Enabled: true, | ||||
| RunAtStart: true, | RunAtStart: true, | ||||
| Schedule: "@every 1m", | |||||
| Schedule: "@every 10m", | |||||
| }, func(ctx context.Context, _ *models.User, _ Config) error { | }, func(ctx context.Context, _ *models.User, _ Config) error { | ||||
| repo.HandleBlockChainUnSuccessRepos() | repo.HandleBlockChainUnSuccessRepos() | ||||
| return nil | return nil | ||||
| @@ -145,7 +145,7 @@ func registerHandleBlockChainMergedPulls() { | |||||
| RegisterTaskFatal("handle_blockchain_merged_pull", &BaseConfig{ | RegisterTaskFatal("handle_blockchain_merged_pull", &BaseConfig{ | ||||
| Enabled: true, | Enabled: true, | ||||
| RunAtStart: true, | RunAtStart: true, | ||||
| Schedule: "@every 1m", | |||||
| Schedule: "@every 10m", | |||||
| }, func(ctx context.Context, _ *models.User, _ Config) error { | }, func(ctx context.Context, _ *models.User, _ Config) error { | ||||
| repo.HandleBlockChainMergedPulls() | repo.HandleBlockChainMergedPulls() | ||||
| return nil | return nil | ||||
| @@ -156,7 +156,7 @@ func registerHandleBlockChainUnSuccessCommits() { | |||||
| RegisterTaskFatal("handle_blockchain_unsuccess_commits", &BaseConfig{ | RegisterTaskFatal("handle_blockchain_unsuccess_commits", &BaseConfig{ | ||||
| Enabled: true, | Enabled: true, | ||||
| RunAtStart: true, | RunAtStart: true, | ||||
| Schedule: "@every 3m", | |||||
| Schedule: "@every 10m", | |||||
| }, func(ctx context.Context, _ *models.User, _ Config) error { | }, func(ctx context.Context, _ *models.User, _ Config) error { | ||||
| repo.HandleBlockChainUnSuccessCommits() | repo.HandleBlockChainUnSuccessCommits() | ||||
| return nil | return nil | ||||
| @@ -185,6 +185,17 @@ func registerHandleSummaryStatistic() { | |||||
| }) | }) | ||||
| } | } | ||||
| func registerSyncCloudbrainStatus() { | |||||
| RegisterTaskFatal("sync_cloudbrain_status", &BaseConfig{ | |||||
| Enabled: true, | |||||
| RunAtStart: false, | |||||
| Schedule: "@every 10m", | |||||
| }, func(ctx context.Context, _ *models.User, _ Config) error { | |||||
| repo.SyncCloudbrainStatus() | |||||
| return nil | |||||
| }) | |||||
| } | |||||
| func initBasicTasks() { | func initBasicTasks() { | ||||
| registerUpdateMirrorTask() | registerUpdateMirrorTask() | ||||
| registerRepoHealthCheck() | registerRepoHealthCheck() | ||||
| @@ -202,4 +213,6 @@ func initBasicTasks() { | |||||
| registerHandleRepoAndUserStatistic() | registerHandleRepoAndUserStatistic() | ||||
| registerHandleSummaryStatistic() | registerHandleSummaryStatistic() | ||||
| registerSyncCloudbrainStatus() | |||||
| } | } | ||||
| @@ -271,6 +271,15 @@ func AllCommitsCount(repoPath string) (int64, error) { | |||||
| return strconv.ParseInt(strings.TrimSpace(stdout), 10, 64) | return strconv.ParseInt(strings.TrimSpace(stdout), 10, 64) | ||||
| } | } | ||||
| func HEADCommitsCount(repoPath string) (int64, error) { | |||||
| stdout, err := NewCommand("rev-list", "HEAD", "--count").RunInDir(repoPath) | |||||
| if err != nil { | |||||
| return 0, err | |||||
| } | |||||
| return strconv.ParseInt(strings.TrimSpace(stdout), 10, 64) | |||||
| } | |||||
| func commitsCount(repoPath, revision, relpath string) (int64, error) { | func commitsCount(repoPath, revision, relpath string) (int64, error) { | ||||
| cmd := NewCommand("rev-list", "--count") | cmd := NewCommand("rev-list", "--count") | ||||
| cmd.AddArguments(revision) | cmd.AddArguments(revision) | ||||
| @@ -52,6 +52,10 @@ func (repo *Repository) GetAllCommitsCount() (int64, error) { | |||||
| return AllCommitsCount(repo.Path) | return AllCommitsCount(repo.Path) | ||||
| } | } | ||||
| func (repo *Repository) GetHeadCommitsCount() (int64, error) { | |||||
| return HEADCommitsCount(repo.Path) | |||||
| } | |||||
| func (repo *Repository) parsePrettyFormatLogToList(logs []byte) (*list.List, error) { | func (repo *Repository) parsePrettyFormatLogToList(logs []byte) (*list.List, error) { | ||||
| l := list.New() | l := list.New() | ||||
| if len(logs) == 0 { | if len(logs) == 0 { | ||||
| @@ -126,7 +126,7 @@ func GetUserKPIStats(repoPath string) (map[string]*UserKPIStats, error) { | |||||
| func SetRepoKPIStats(repoPath string, fromTime time.Time, stats *RepoKPIStats, newContributers map[string]struct{}) error { | func SetRepoKPIStats(repoPath string, fromTime time.Time, stats *RepoKPIStats, newContributers map[string]struct{}) error { | ||||
| since := fromTime.Format(time.RFC3339) | since := fromTime.Format(time.RFC3339) | ||||
| args := []string{"log", "--numstat", "--no-merges", "--branches=*", "--pretty=format:---%n%h%n%an%n%ae%n", "--date=iso", fmt.Sprintf("--since='%s'", since)} | |||||
| args := []string{"log", "--numstat", "--no-merges", "HEAD", "--pretty=format:---%n%h%n%an%n%ae%n", "--date=iso", fmt.Sprintf("--since='%s'", since)} | |||||
| stdout, err := NewCommand(args...).RunInDirBytes(repoPath) | stdout, err := NewCommand(args...).RunInDirBytes(repoPath) | ||||
| if err != nil { | if err != nil { | ||||
| @@ -212,7 +212,7 @@ func SetRepoKPIStats(repoPath string, fromTime time.Time, stats *RepoKPIStats, n | |||||
| func GetContributorsDetail(repoPath string, fromTime time.Time) ([]Contributor, error) { | func GetContributorsDetail(repoPath string, fromTime time.Time) ([]Contributor, error) { | ||||
| since := fromTime.Format(time.RFC3339) | since := fromTime.Format(time.RFC3339) | ||||
| cmd := NewCommand("shortlog", "-sne", "--all", fmt.Sprintf("--since='%s'", since)) | |||||
| cmd := NewCommand("shortlog", "-sne", "HEAD", fmt.Sprintf("--since='%s'", since)) | |||||
| stdout, err := cmd.RunInDir(repoPath) | stdout, err := cmd.RunInDir(repoPath) | ||||
| if err != nil { | if err != nil { | ||||
| return nil, err | return nil, err | ||||
| @@ -13,6 +13,9 @@ import ( | |||||
| "strings" | "strings" | ||||
| "time" | "time" | ||||
| "code.gitea.io/gitea/modules/setting" | |||||
| "golang.org/x/net/proxy" | |||||
| "code.gitea.io/gitea/modules/log" | "code.gitea.io/gitea/modules/log" | ||||
| "code.gitea.io/gitea/modules/migrations/base" | "code.gitea.io/gitea/modules/migrations/base" | ||||
| "code.gitea.io/gitea/modules/structs" | "code.gitea.io/gitea/modules/structs" | ||||
| @@ -98,13 +101,41 @@ func NewGithubDownloaderV3(userName, password, repoOwner, repoName string) *Gith | |||||
| ) | ) | ||||
| client = oauth2.NewClient(downloader.ctx, ts) | client = oauth2.NewClient(downloader.ctx, ts) | ||||
| } else { | } else { | ||||
| client = &http.Client{ | |||||
| Transport: &http.Transport{ | |||||
| Proxy: func(req *http.Request) (*url.URL, error) { | |||||
| req.SetBasicAuth(userName, password) | |||||
| return nil, nil | |||||
| if setting.Migrations.Proxy != "" { | |||||
| contextDialer, err := getProxyDialContext() | |||||
| if err != nil { | |||||
| log.Warn("Failed to use proxy for Github.", err) | |||||
| client = &http.Client{ | |||||
| Transport: &http.Transport{ | |||||
| Proxy: func(req *http.Request) (*url.URL, error) { | |||||
| req.SetBasicAuth(userName, password) | |||||
| return nil, nil | |||||
| }, | |||||
| }, | |||||
| } | |||||
| } else { | |||||
| client = &http.Client{ | |||||
| Transport: &http.Transport{ | |||||
| Proxy: func(req *http.Request) (*url.URL, error) { | |||||
| req.SetBasicAuth(userName, password) | |||||
| return nil, nil | |||||
| }, | |||||
| DialContext: contextDialer.DialContext, | |||||
| }, | |||||
| } | |||||
| } | |||||
| } else { | |||||
| client = &http.Client{ | |||||
| Transport: &http.Transport{ | |||||
| Proxy: func(req *http.Request) (*url.URL, error) { | |||||
| req.SetBasicAuth(userName, password) | |||||
| return nil, nil | |||||
| }, | |||||
| }, | }, | ||||
| }, | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -112,6 +143,25 @@ func NewGithubDownloaderV3(userName, password, repoOwner, repoName string) *Gith | |||||
| return &downloader | return &downloader | ||||
| } | } | ||||
| func getProxyDialContext() (proxy.ContextDialer, error) { | |||||
| authInfo := &proxy.Auth{ | |||||
| setting.Migrations.Username, | |||||
| setting.Migrations.Password, | |||||
| } | |||||
| dialSocksProxy, err := proxy.SOCKS5("tcp", setting.Migrations.Proxy, authInfo, proxy.Direct) | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| if contextDialer, ok := dialSocksProxy.(proxy.ContextDialer); ok { | |||||
| return contextDialer, nil | |||||
| } else { | |||||
| return nil, fmt.Errorf("It is not a valiad dialer.") | |||||
| } | |||||
| } | |||||
| // SetContext set context | // SetContext set context | ||||
| func (g *GithubDownloaderV3) SetContext(ctx context.Context) { | func (g *GithubDownloaderV3) SetContext(ctx context.Context) { | ||||
| g.ctx = ctx | g.ctx = ctx | ||||
| @@ -48,8 +48,12 @@ const ( | |||||
| PerPage = 10 | PerPage = 10 | ||||
| IsLatestVersion = "1" | IsLatestVersion = "1" | ||||
| NotLatestVersion = "0" | NotLatestVersion = "0" | ||||
| ComputeResource = "NPU" | |||||
| VersionCount = 1 | |||||
| // ComputeResource = "NPU" | |||||
| NPUResource = "NPU" | |||||
| GPUResource = "CPU/GPU" | |||||
| AllResource = "all" | |||||
| DebugType = -1 | |||||
| VersionCount = 1 | |||||
| SortByCreateTime = "create_time" | SortByCreateTime = "create_time" | ||||
| ConfigTypeCustom = "custom" | ConfigTypeCustom = "custom" | ||||
| @@ -273,7 +277,7 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error | |||||
| DatasetName: attach.Name, | DatasetName: attach.Name, | ||||
| CommitID: req.CommitID, | CommitID: req.CommitID, | ||||
| IsLatestVersion: req.IsLatestVersion, | IsLatestVersion: req.IsLatestVersion, | ||||
| ComputeResource: ComputeResource, | |||||
| ComputeResource: NPUResource, | |||||
| EngineID: req.EngineID, | EngineID: req.EngineID, | ||||
| TrainUrl: req.TrainUrl, | TrainUrl: req.TrainUrl, | ||||
| BranchName: req.BranchName, | BranchName: req.BranchName, | ||||
| @@ -356,7 +360,7 @@ func GenerateTrainJobVersion(ctx *context.Context, req *GenerateTrainJobReq, job | |||||
| CommitID: req.CommitID, | CommitID: req.CommitID, | ||||
| IsLatestVersion: req.IsLatestVersion, | IsLatestVersion: req.IsLatestVersion, | ||||
| PreVersionName: req.PreVersionName, | PreVersionName: req.PreVersionName, | ||||
| ComputeResource: ComputeResource, | |||||
| ComputeResource: NPUResource, | |||||
| EngineID: req.EngineID, | EngineID: req.EngineID, | ||||
| TrainUrl: req.TrainUrl, | TrainUrl: req.TrainUrl, | ||||
| BranchName: req.BranchName, | BranchName: req.BranchName, | ||||
| @@ -4,6 +4,8 @@ import ( | |||||
| "code.gitea.io/gitea/modules/setting" | "code.gitea.io/gitea/modules/setting" | ||||
| ) | ) | ||||
| const MAX_LINES_RECORD = 100 | |||||
| func Normalization(value float64, minValue float64, maxValue float64) float64 { | func Normalization(value float64, minValue float64, maxValue float64) float64 { | ||||
| min := int64(minValue * 100) | min := int64(minValue * 100) | ||||
| @@ -72,9 +74,12 @@ func GetTeamHealthInitValue(contributors int64, keyContributors int64, newContri | |||||
| } | } | ||||
| func GetRepoGrowthInitValue(codelinesGrowth int64, issueGrowth int64, commitsGrowth int64, newContributors int64, commentsGrowth int64) float64 { | |||||
| return setting.RadarMap.GrowthCodeLines*float64(codelinesGrowth) + | |||||
| func GetRepoGrowthInitValue(codeLinesGrowth int64, issueGrowth int64, commitsGrowth int64, newContributors int64, commentsGrowth int64) float64 { | |||||
| codeLinesKB := codeLinesGrowth / 1000 | |||||
| if codeLinesKB > MAX_LINES_RECORD { | |||||
| codeLinesKB = MAX_LINES_RECORD | |||||
| } | |||||
| return setting.RadarMap.GrowthCodeLines*float64(codeLinesKB) + | |||||
| setting.RadarMap.GrowthIssue*float64(issueGrowth) + | setting.RadarMap.GrowthIssue*float64(issueGrowth) + | ||||
| setting.RadarMap.GrowthCommit*float64(commitsGrowth) + | setting.RadarMap.GrowthCommit*float64(commitsGrowth) + | ||||
| setting.RadarMap.GrowthContributors*float64(newContributors) + | setting.RadarMap.GrowthContributors*float64(newContributors) + | ||||
| @@ -6,6 +6,7 @@ package repository | |||||
| import ( | import ( | ||||
| "fmt" | "fmt" | ||||
| "net/url" | |||||
| "os" | "os" | ||||
| "path" | "path" | ||||
| "strings" | "strings" | ||||
| @@ -54,29 +55,34 @@ func MigrateRepositoryGitData(doer, u *models.User, repo *models.Repository, opt | |||||
| repo.NumWatches = 1 | repo.NumWatches = 1 | ||||
| } | } | ||||
| migrateTimeout := time.Duration(setting.Git.Timeout.Migrate) * time.Second | |||||
| migrateTimeout := getMigrateTimeout(opts.CloneAddr) | |||||
| var err error | var err error | ||||
| if err = os.RemoveAll(repoPath); err != nil { | if err = os.RemoveAll(repoPath); err != nil { | ||||
| return repo, fmt.Errorf("Failed to remove %s: %v", repoPath, err) | return repo, fmt.Errorf("Failed to remove %s: %v", repoPath, err) | ||||
| } | } | ||||
| log.Info("clone begin:" + opts.CloneAddr) | |||||
| if err = git.Clone(opts.CloneAddr, repoPath, git.CloneRepoOptions{ | if err = git.Clone(opts.CloneAddr, repoPath, git.CloneRepoOptions{ | ||||
| Mirror: true, | Mirror: true, | ||||
| Quiet: true, | Quiet: true, | ||||
| Timeout: migrateTimeout, | Timeout: migrateTimeout, | ||||
| }); err != nil { | }); err != nil { | ||||
| log.Warn("clone err") | |||||
| return repo, fmt.Errorf("Clone: %v", err) | return repo, fmt.Errorf("Clone: %v", err) | ||||
| } | } | ||||
| log.Info("clone end:" + opts.CloneAddr) | |||||
| if opts.Wiki { | if opts.Wiki { | ||||
| log.Info("test wiki path begin") | |||||
| wikiPath := models.WikiPath(u.Name, opts.RepoName) | wikiPath := models.WikiPath(u.Name, opts.RepoName) | ||||
| wikiRemotePath := wikiRemoteURL(opts.CloneAddr) | wikiRemotePath := wikiRemoteURL(opts.CloneAddr) | ||||
| log.Info("test wiki path end") | |||||
| if len(wikiRemotePath) > 0 { | if len(wikiRemotePath) > 0 { | ||||
| if err := os.RemoveAll(wikiPath); err != nil { | if err := os.RemoveAll(wikiPath); err != nil { | ||||
| return repo, fmt.Errorf("Failed to remove %s: %v", wikiPath, err) | return repo, fmt.Errorf("Failed to remove %s: %v", wikiPath, err) | ||||
| } | } | ||||
| log.Info("wiki clone begin") | |||||
| if err = git.Clone(wikiRemotePath, wikiPath, git.CloneRepoOptions{ | if err = git.Clone(wikiRemotePath, wikiPath, git.CloneRepoOptions{ | ||||
| Mirror: true, | Mirror: true, | ||||
| Quiet: true, | Quiet: true, | ||||
| @@ -88,6 +94,7 @@ func MigrateRepositoryGitData(doer, u *models.User, repo *models.Repository, opt | |||||
| return repo, fmt.Errorf("Failed to remove %s: %v", wikiPath, err) | return repo, fmt.Errorf("Failed to remove %s: %v", wikiPath, err) | ||||
| } | } | ||||
| } | } | ||||
| log.Info("wiki clone end") | |||||
| } | } | ||||
| } | } | ||||
| @@ -137,9 +144,20 @@ func MigrateRepositoryGitData(doer, u *models.User, repo *models.Repository, opt | |||||
| repo, err = CleanUpMigrateInfo(repo) | repo, err = CleanUpMigrateInfo(repo) | ||||
| } | } | ||||
| log.Info("clone all end:" + opts.CloneAddr) | |||||
| return repo, err | return repo, err | ||||
| } | } | ||||
| func getMigrateTimeout(urlClone string) time.Duration { | |||||
| u, err := url.Parse(urlClone) | |||||
| if err == nil && strings.EqualFold(u.Host, "github.com") { | |||||
| return time.Duration(setting.Git.Timeout.GitHubMigrate) * time.Second | |||||
| } | |||||
| return time.Duration(setting.Git.Timeout.Migrate) * time.Second | |||||
| } | |||||
| // cleanUpMigrateGitConfig removes mirror info which prevents "push --all". | // cleanUpMigrateGitConfig removes mirror info which prevents "push --all". | ||||
| // This also removes possible user credentials. | // This also removes possible user credentials. | ||||
| func cleanUpMigrateGitConfig(configPath string) error { | func cleanUpMigrateGitConfig(configPath string) error { | ||||
| @@ -27,12 +27,13 @@ var ( | |||||
| EnableAutoGitWireProtocol bool | EnableAutoGitWireProtocol bool | ||||
| PullRequestPushMessage bool | PullRequestPushMessage bool | ||||
| Timeout struct { | Timeout struct { | ||||
| Default int | |||||
| Migrate int | |||||
| Mirror int | |||||
| Clone int | |||||
| Pull int | |||||
| GC int `ini:"GC"` | |||||
| Default int | |||||
| Migrate int | |||||
| GitHubMigrate int | |||||
| Mirror int | |||||
| Clone int | |||||
| Pull int | |||||
| GC int `ini:"GC"` | |||||
| } `ini:"git.timeout"` | } `ini:"git.timeout"` | ||||
| }{ | }{ | ||||
| DisableDiffHighlight: false, | DisableDiffHighlight: false, | ||||
| @@ -45,19 +46,21 @@ var ( | |||||
| EnableAutoGitWireProtocol: true, | EnableAutoGitWireProtocol: true, | ||||
| PullRequestPushMessage: true, | PullRequestPushMessage: true, | ||||
| Timeout: struct { | Timeout: struct { | ||||
| Default int | |||||
| Migrate int | |||||
| Mirror int | |||||
| Clone int | |||||
| Pull int | |||||
| GC int `ini:"GC"` | |||||
| Default int | |||||
| Migrate int | |||||
| GitHubMigrate int | |||||
| Mirror int | |||||
| Clone int | |||||
| Pull int | |||||
| GC int `ini:"GC"` | |||||
| }{ | }{ | ||||
| Default: int(git.DefaultCommandExecutionTimeout / time.Second), | |||||
| Migrate: 600, | |||||
| Mirror: 300, | |||||
| Clone: 300, | |||||
| Pull: 300, | |||||
| GC: 60, | |||||
| Default: int(git.DefaultCommandExecutionTimeout / time.Second), | |||||
| Migrate: 900, | |||||
| GitHubMigrate: 1800, | |||||
| Mirror: 1200, | |||||
| Clone: 300, | |||||
| Pull: 300, | |||||
| GC: 60, | |||||
| }, | }, | ||||
| } | } | ||||
| ) | ) | ||||
| @@ -83,6 +83,7 @@ func newIndexerService() { | |||||
| Indexer.UpdateQueueLength = sec.Key("UPDATE_BUFFER_LEN").MustInt(20) | Indexer.UpdateQueueLength = sec.Key("UPDATE_BUFFER_LEN").MustInt(20) | ||||
| Indexer.MaxIndexerFileSize = sec.Key("MAX_FILE_SIZE").MustInt64(1024 * 1024) | Indexer.MaxIndexerFileSize = sec.Key("MAX_FILE_SIZE").MustInt64(1024 * 1024) | ||||
| Indexer.StartupTimeout = sec.Key("STARTUP_TIMEOUT").MustDuration(30 * time.Second) | Indexer.StartupTimeout = sec.Key("STARTUP_TIMEOUT").MustDuration(30 * time.Second) | ||||
| log.Info("New IndexerService Inited.") | |||||
| } | } | ||||
| // IndexerGlobFromString parses a comma separated list of patterns and returns a glob.Glob slice suited for repo indexing | // IndexerGlobFromString parses a comma separated list of patterns and returns a glob.Glob slice suited for repo indexing | ||||
| @@ -9,6 +9,9 @@ var ( | |||||
| Migrations = struct { | Migrations = struct { | ||||
| MaxAttempts int | MaxAttempts int | ||||
| RetryBackoff int | RetryBackoff int | ||||
| Proxy string | |||||
| Username string | |||||
| Password string | |||||
| }{ | }{ | ||||
| MaxAttempts: 3, | MaxAttempts: 3, | ||||
| RetryBackoff: 3, | RetryBackoff: 3, | ||||
| @@ -19,4 +22,7 @@ func newMigrationsService() { | |||||
| sec := Cfg.Section("migrations") | sec := Cfg.Section("migrations") | ||||
| Migrations.MaxAttempts = sec.Key("MAX_ATTEMPTS").MustInt(Migrations.MaxAttempts) | Migrations.MaxAttempts = sec.Key("MAX_ATTEMPTS").MustInt(Migrations.MaxAttempts) | ||||
| Migrations.RetryBackoff = sec.Key("RETRY_BACKOFF").MustInt(Migrations.RetryBackoff) | Migrations.RetryBackoff = sec.Key("RETRY_BACKOFF").MustInt(Migrations.RetryBackoff) | ||||
| Migrations.Proxy = sec.Key("Proxy").MustString("") | |||||
| Migrations.Username = sec.Key("Username").MustString("") | |||||
| Migrations.Password = sec.Key("Password").MustString("") | |||||
| } | } | ||||
| @@ -160,6 +160,7 @@ func NewQueueService() { | |||||
| if _, ok := sectionMap["LENGTH"]; !ok { | if _, ok := sectionMap["LENGTH"]; !ok { | ||||
| _, _ = section.NewKey("LENGTH", fmt.Sprintf("%d", Repository.PullRequestQueueLength)) | _, _ = section.NewKey("LENGTH", fmt.Sprintf("%d", Repository.PullRequestQueueLength)) | ||||
| } | } | ||||
| log.Info("New QueueService Inited.") | |||||
| } | } | ||||
| // ParseQueueConnStr parses a queue connection string | // ParseQueueConnStr parses a queue connection string | ||||
| @@ -433,35 +433,43 @@ var ( | |||||
| AuthUser string | AuthUser string | ||||
| AuthPassword string | AuthPassword string | ||||
| //home page | |||||
| RecommentRepoAddr string | |||||
| //labelsystem config | //labelsystem config | ||||
| LabelTaskName string | LabelTaskName string | ||||
| LabelDatasetDeleteQueue string | LabelDatasetDeleteQueue string | ||||
| DecompressOBSTaskName string | DecompressOBSTaskName string | ||||
| //cloudbrain config | //cloudbrain config | ||||
| CBAuthUser string | |||||
| CBAuthPassword string | |||||
| RestServerHost string | |||||
| JobPath string | |||||
| JobType string | |||||
| GpuTypes string | |||||
| DebugServerHost string | |||||
| ResourceSpecs string | |||||
| CBAuthUser string | |||||
| CBAuthPassword string | |||||
| RestServerHost string | |||||
| JobPath string | |||||
| CBCodePathPrefix string | |||||
| JobType string | |||||
| GpuTypes string | |||||
| DebugServerHost string | |||||
| ResourceSpecs string | |||||
| MaxDuration int64 | |||||
| //benchmark config | //benchmark config | ||||
| IsBenchmarkEnabled bool | IsBenchmarkEnabled bool | ||||
| BenchmarkCode string | |||||
| BenchmarkOwner string | |||||
| BenchmarkName string | |||||
| BenchmarkServerHost string | BenchmarkServerHost string | ||||
| BenchmarkCategory string | BenchmarkCategory string | ||||
| //snn4imagenet config | //snn4imagenet config | ||||
| IsSnn4imagenetEnabled bool | IsSnn4imagenetEnabled bool | ||||
| Snn4imagenetCode string | |||||
| Snn4imagenetOwner string | |||||
| Snn4imagenetName string | |||||
| Snn4imagenetServerHost string | Snn4imagenetServerHost string | ||||
| //snn4imagenet config | //snn4imagenet config | ||||
| IsBrainScoreEnabled bool | IsBrainScoreEnabled bool | ||||
| BrainScoreCode string | |||||
| BrainScoreOwner string | |||||
| BrainScoreName string | |||||
| BrainScoreServerHost string | BrainScoreServerHost string | ||||
| //blockchain config | //blockchain config | ||||
| @@ -549,7 +557,7 @@ var ( | |||||
| RecordBeginTime string | RecordBeginTime string | ||||
| IgnoreMirrorRepo bool | IgnoreMirrorRepo bool | ||||
| }{} | }{} | ||||
| Warn_Notify_Mails []string | Warn_Notify_Mails []string | ||||
| ) | ) | ||||
| @@ -1216,51 +1224,59 @@ func NewContext() { | |||||
| sec = Cfg.Section("decompress") | sec = Cfg.Section("decompress") | ||||
| DecompressAddress = sec.Key("HOST").MustString("http://192.168.207.34:39987") | DecompressAddress = sec.Key("HOST").MustString("http://192.168.207.34:39987") | ||||
| AuthUser = sec.Key("USER").MustString("cW4cMtH24eoWPE7X") | |||||
| AuthPassword = sec.Key("PASSWORD").MustString("4BPmgvK2hb2Eywwyp4YZRY4B7yQf4DAC") | |||||
| AuthUser = sec.Key("USER").MustString("") | |||||
| AuthPassword = sec.Key("PASSWORD").MustString("") | |||||
| sec = Cfg.Section("labelsystem") | sec = Cfg.Section("labelsystem") | ||||
| LabelTaskName = sec.Key("LabelTaskName").MustString("LabelRedisQueue") | LabelTaskName = sec.Key("LabelTaskName").MustString("LabelRedisQueue") | ||||
| LabelDatasetDeleteQueue = sec.Key("LabelDatasetDeleteQueue").MustString("LabelDatasetDeleteQueue") | LabelDatasetDeleteQueue = sec.Key("LabelDatasetDeleteQueue").MustString("LabelDatasetDeleteQueue") | ||||
| DecompressOBSTaskName = sec.Key("DecompressOBSTaskName").MustString("LabelDecompressOBSQueue") | DecompressOBSTaskName = sec.Key("DecompressOBSTaskName").MustString("LabelDecompressOBSQueue") | ||||
| sec = Cfg.Section("homepage") | |||||
| RecommentRepoAddr = sec.Key("Address").MustString("https://git.openi.org.cn/OpenIOSSG/promote/raw/branch/master/") | |||||
| sec = Cfg.Section("cloudbrain") | sec = Cfg.Section("cloudbrain") | ||||
| CBAuthUser = sec.Key("USER").MustString("cW4cMtH24eoWPE7X") | |||||
| CBAuthPassword = sec.Key("PWD").MustString("4BPmgvK2hb2Eywwyp4YZRY4B7yQf4DAC") | |||||
| CBAuthUser = sec.Key("USER").MustString("") | |||||
| CBAuthPassword = sec.Key("PWD").MustString("") | |||||
| RestServerHost = sec.Key("REST_SERVER_HOST").MustString("http://192.168.202.73") | RestServerHost = sec.Key("REST_SERVER_HOST").MustString("http://192.168.202.73") | ||||
| JobPath = sec.Key("JOB_PATH").MustString("/datasets/minio/data/opendata/jobs/") | JobPath = sec.Key("JOB_PATH").MustString("/datasets/minio/data/opendata/jobs/") | ||||
| CBCodePathPrefix = sec.Key("CODE_PATH_PREFIX").MustString("jobs/") | |||||
| DebugServerHost = sec.Key("DEBUG_SERVER_HOST").MustString("http://192.168.202.73") | DebugServerHost = sec.Key("DEBUG_SERVER_HOST").MustString("http://192.168.202.73") | ||||
| JobType = sec.Key("GPU_TYPE_DEFAULT").MustString("openidebug") | JobType = sec.Key("GPU_TYPE_DEFAULT").MustString("openidebug") | ||||
| GpuTypes = sec.Key("GPU_TYPES").MustString("") | GpuTypes = sec.Key("GPU_TYPES").MustString("") | ||||
| ResourceSpecs = sec.Key("RESOURCE_SPECS").MustString("") | ResourceSpecs = sec.Key("RESOURCE_SPECS").MustString("") | ||||
| MaxDuration = sec.Key("MAX_DURATION").MustInt64(14400) | |||||
| sec = Cfg.Section("benchmark") | sec = Cfg.Section("benchmark") | ||||
| IsBenchmarkEnabled = sec.Key("ENABLED").MustBool(false) | IsBenchmarkEnabled = sec.Key("ENABLED").MustBool(false) | ||||
| BenchmarkCode = sec.Key("BENCHMARKCODE").MustString("https://yangzhx:justfortest123@git.openi.org.cn/yangzhx/detection_benchmark_script.git") | |||||
| BenchmarkServerHost = sec.Key("HOST").MustString("http://192.168.202.90:3366/") | |||||
| BenchmarkOwner = sec.Key("OWNER").MustString("") | |||||
| BenchmarkName = sec.Key("NAME").MustString("") | |||||
| BenchmarkServerHost = sec.Key("HOST").MustString("") | |||||
| BenchmarkCategory = sec.Key("CATEGORY").MustString("") | BenchmarkCategory = sec.Key("CATEGORY").MustString("") | ||||
| sec = Cfg.Section("snn4imagenet") | sec = Cfg.Section("snn4imagenet") | ||||
| IsSnn4imagenetEnabled = sec.Key("ENABLED").MustBool(false) | IsSnn4imagenetEnabled = sec.Key("ENABLED").MustBool(false) | ||||
| Snn4imagenetCode = sec.Key("SNN4IMAGENETCODE").MustString("https://yult:19910821ylt@git.openi.org.cn/yult/snn4imagenet_script.git") | |||||
| Snn4imagenetServerHost = sec.Key("HOST").MustString("http://192.168.207.76:8080/") | |||||
| Snn4imagenetOwner = sec.Key("OWNER").MustString("") | |||||
| Snn4imagenetName = sec.Key("NAME").MustString("") | |||||
| Snn4imagenetServerHost = sec.Key("HOST").MustString("") | |||||
| sec = Cfg.Section("brainscore") | sec = Cfg.Section("brainscore") | ||||
| IsBrainScoreEnabled = sec.Key("ENABLED").MustBool(false) | IsBrainScoreEnabled = sec.Key("ENABLED").MustBool(false) | ||||
| BrainScoreCode = sec.Key("BRAINSCORECODE").MustString("https://yult:19910821ylt@git.openi.org.cn/yult/brainscore_script.git") | |||||
| BrainScoreServerHost = sec.Key("HOST").MustString("http://192.168.207.76:8080/") | |||||
| BrainScoreOwner = sec.Key("OWNER").MustString("") | |||||
| BrainScoreName = sec.Key("NAME").MustString("") | |||||
| BrainScoreServerHost = sec.Key("HOST").MustString("") | |||||
| sec = Cfg.Section("blockchain") | sec = Cfg.Section("blockchain") | ||||
| BlockChainHost = sec.Key("HOST").MustString("http://192.168.136.66:3302/") | BlockChainHost = sec.Key("HOST").MustString("http://192.168.136.66:3302/") | ||||
| CommitValidDate = sec.Key("COMMIT_VALID_DATE").MustString("2021-01-15") | CommitValidDate = sec.Key("COMMIT_VALID_DATE").MustString("2021-01-15") | ||||
| sec = Cfg.Section("obs") | sec = Cfg.Section("obs") | ||||
| Endpoint = sec.Key("ENDPOINT").MustString("112.95.163.82") | |||||
| Endpoint = sec.Key("ENDPOINT").MustString("") | |||||
| AccessKeyID = sec.Key("ACCESS_KEY_ID").MustString("") | AccessKeyID = sec.Key("ACCESS_KEY_ID").MustString("") | ||||
| SecretAccessKey = sec.Key("SECRET_ACCESS_KEY").MustString("") | SecretAccessKey = sec.Key("SECRET_ACCESS_KEY").MustString("") | ||||
| Bucket = sec.Key("BUCKET").MustString("testopendata") | |||||
| Location = sec.Key("LOCATION").MustString("cn-south-222") | |||||
| BasePath = sec.Key("BASE_PATH").MustString("attachment/") | |||||
| Bucket = sec.Key("BUCKET").MustString("") | |||||
| Location = sec.Key("LOCATION").MustString("") | |||||
| BasePath = sec.Key("BASE_PATH").MustString("") | |||||
| TrainJobModelPath = sec.Key("TrainJobModel_Path").MustString("job/") | TrainJobModelPath = sec.Key("TrainJobModel_Path").MustString("job/") | ||||
| OutPutPath = sec.Key("Output_Path").MustString("output/") | OutPutPath = sec.Key("Output_Path").MustString("output/") | ||||
| CodePathPrefix = sec.Key("CODE_PATH_PREFIX").MustString("code/") | CodePathPrefix = sec.Key("CODE_PATH_PREFIX").MustString("code/") | ||||
| @@ -1268,17 +1284,17 @@ func NewContext() { | |||||
| PROXYURL = sec.Key("PROXY_URL").MustString("") | PROXYURL = sec.Key("PROXY_URL").MustString("") | ||||
| sec = Cfg.Section("modelarts") | sec = Cfg.Section("modelarts") | ||||
| ModelArtsHost = sec.Key("ENDPOINT").MustString("112.95.163.80") | |||||
| IamHost = sec.Key("IAMHOST").MustString("112.95.163.80") | |||||
| ModelArtsHost = sec.Key("ENDPOINT").MustString("") | |||||
| IamHost = sec.Key("IAMHOST").MustString("") | |||||
| ProjectID = sec.Key("PROJECT_ID").MustString("") | ProjectID = sec.Key("PROJECT_ID").MustString("") | ||||
| ProjectName = sec.Key("PROJECT_NAME").MustString("") | ProjectName = sec.Key("PROJECT_NAME").MustString("") | ||||
| ModelArtsUsername = sec.Key("USERNAME").MustString("") | ModelArtsUsername = sec.Key("USERNAME").MustString("") | ||||
| ModelArtsPassword = sec.Key("PASSWORD").MustString("") | ModelArtsPassword = sec.Key("PASSWORD").MustString("") | ||||
| ModelArtsDomain = sec.Key("DOMAIN").MustString("cn-south-222") | |||||
| ModelArtsDomain = sec.Key("DOMAIN").MustString("") | |||||
| AllowedOrg = sec.Key("ORGANIZATION").MustString("") | AllowedOrg = sec.Key("ORGANIZATION").MustString("") | ||||
| ProfileID = sec.Key("PROFILE_ID").MustString("") | ProfileID = sec.Key("PROFILE_ID").MustString("") | ||||
| PoolInfos = sec.Key("POOL_INFOS").MustString("") | PoolInfos = sec.Key("POOL_INFOS").MustString("") | ||||
| Flavor = sec.Key("FLAVOR").MustString("modelarts.bm.910.arm.public.2") | |||||
| Flavor = sec.Key("FLAVOR").MustString("") | |||||
| ResourcePools = sec.Key("Resource_Pools").MustString("") | ResourcePools = sec.Key("Resource_Pools").MustString("") | ||||
| Engines = sec.Key("Engines").MustString("") | Engines = sec.Key("Engines").MustString("") | ||||
| EngineVersions = sec.Key("Engine_Versions").MustString("") | EngineVersions = sec.Key("Engine_Versions").MustString("") | ||||
| @@ -1286,10 +1302,10 @@ func NewContext() { | |||||
| TrainJobFLAVORINFOS = sec.Key("TrainJob_FLAVOR_INFOS").MustString("") | TrainJobFLAVORINFOS = sec.Key("TrainJob_FLAVOR_INFOS").MustString("") | ||||
| sec = Cfg.Section("elk") | sec = Cfg.Section("elk") | ||||
| ElkUrl = sec.Key("ELKURL").MustString("http://192.168.207.35:5601/internal/bsearch") | |||||
| ElkUser = sec.Key("ELKUSER").MustString("Qizhi") | |||||
| ElkPassword = sec.Key("ELKPASSWORD").MustString("Pcl2020") | |||||
| Index = sec.Key("INDEX").MustString("filebeat-7.3.2*") | |||||
| ElkUrl = sec.Key("ELKURL").MustString("") | |||||
| ElkUser = sec.Key("ELKUSER").MustString("") | |||||
| ElkPassword = sec.Key("ELKPASSWORD").MustString("") | |||||
| Index = sec.Key("INDEX").MustString("") | |||||
| TimeField = sec.Key("TIMEFIELD").MustString(" @timestamptest") | TimeField = sec.Key("TIMEFIELD").MustString(" @timestamptest") | ||||
| ElkTimeFormat = sec.Key("ELKTIMEFORMAT").MustString("date_time") | ElkTimeFormat = sec.Key("ELKTIMEFORMAT").MustString("date_time") | ||||
| @@ -1313,7 +1329,7 @@ func SetRadarMapConfig() { | |||||
| RadarMap.CompletenessIssuesClosed = sec.Key("completeness_issues_closed").MustFloat64(0.2) | RadarMap.CompletenessIssuesClosed = sec.Key("completeness_issues_closed").MustFloat64(0.2) | ||||
| RadarMap.CompletenessReleases = sec.Key("completeness_releases").MustFloat64(0.3) | RadarMap.CompletenessReleases = sec.Key("completeness_releases").MustFloat64(0.3) | ||||
| RadarMap.CompletenessDevelopAge = sec.Key("completeness_develop_age").MustFloat64(0.1) | RadarMap.CompletenessDevelopAge = sec.Key("completeness_develop_age").MustFloat64(0.1) | ||||
| RadarMap.CompletenessDataset = sec.Key("completeness_dataset").MustFloat64(0.1) | |||||
| RadarMap.CompletenessDataset = sec.Key("completeness_dataset").MustFloat64(0) | |||||
| RadarMap.CompletenessModel = sec.Key("completeness_model").MustFloat64(0.1) | RadarMap.CompletenessModel = sec.Key("completeness_model").MustFloat64(0.1) | ||||
| RadarMap.CompletenessWiki = sec.Key("completeness_wiki").MustFloat64(0.1) | RadarMap.CompletenessWiki = sec.Key("completeness_wiki").MustFloat64(0.1) | ||||
| RadarMap.Liveness = sec.Key("liveness").MustFloat64(0.3) | RadarMap.Liveness = sec.Key("liveness").MustFloat64(0.3) | ||||
| @@ -48,4 +48,5 @@ func newWebhookService() { | |||||
| } | } | ||||
| } | } | ||||
| Webhook.ProxyHosts = sec.Key("PROXY_HOSTS").Strings(",") | Webhook.ProxyHosts = sec.Key("PROXY_HOSTS").Strings(",") | ||||
| log.Info("New WebhookService Inited.") | |||||
| } | } | ||||
| @@ -76,3 +76,7 @@ func (l *LocalStorage) PresignedPutURL(path string) (string, error) { | |||||
| func (l *LocalStorage) HasObject(path string) (bool, error) { | func (l *LocalStorage) HasObject(path string) (bool, error) { | ||||
| return false, nil | return false, nil | ||||
| } | } | ||||
| func (l *LocalStorage) UploadObject(fileName, filePath string) error { | |||||
| return nil | |||||
| } | |||||
| @@ -122,3 +122,9 @@ func (m *MinioStorage) HasObject(path string) (bool, error) { | |||||
| return hasObject, nil | return hasObject, nil | ||||
| } | } | ||||
| //upload object | |||||
| func (m *MinioStorage) UploadObject(fileName, filePath string) error { | |||||
| _, err := m.client.FPutObject(m.bucket, fileName, filePath, minio.PutObjectOptions{}) | |||||
| return err | |||||
| } | |||||
| @@ -5,6 +5,7 @@ | |||||
| package storage | package storage | ||||
| import ( | import ( | ||||
| "errors" | |||||
| "io" | "io" | ||||
| "net/url" | "net/url" | ||||
| "path" | "path" | ||||
| @@ -140,11 +141,51 @@ func ObsMultiPartUpload(uuid string, uploadId string, partNumber int, fileName s | |||||
| } | } | ||||
| func ObsDownload(uuid string, fileName string) (io.ReadCloser, error) { | |||||
| //delete all file under the dir path | |||||
| func ObsRemoveObject(bucket string, path string) error { | |||||
| log.Info("Bucket=" + bucket + " path=" + path) | |||||
| if len(path) == 0 { | |||||
| return errors.New("path canot be null.") | |||||
| } | |||||
| input := &obs.ListObjectsInput{} | |||||
| input.Bucket = bucket | |||||
| // 设置每页100个对象 | |||||
| input.MaxKeys = 100 | |||||
| input.Prefix = path | |||||
| index := 1 | |||||
| log.Info("prefix=" + input.Prefix) | |||||
| for { | |||||
| output, err := ObsCli.ListObjects(input) | |||||
| if err == nil { | |||||
| log.Info("Page:%d\n", index) | |||||
| index++ | |||||
| for _, val := range output.Contents { | |||||
| log.Info("delete obs file:" + val.Key) | |||||
| delObj := &obs.DeleteObjectInput{} | |||||
| delObj.Bucket = setting.Bucket | |||||
| delObj.Key = val.Key | |||||
| ObsCli.DeleteObject(delObj) | |||||
| } | |||||
| if output.IsTruncated { | |||||
| input.Marker = output.NextMarker | |||||
| } else { | |||||
| break | |||||
| } | |||||
| } else { | |||||
| if obsError, ok := err.(obs.ObsError); ok { | |||||
| log.Info("Code:%s\n", obsError.Code) | |||||
| log.Info("Message:%s\n", obsError.Message) | |||||
| } | |||||
| return err | |||||
| } | |||||
| } | |||||
| return nil | |||||
| } | |||||
| func ObsDownloadAFile(bucket string, key string) (io.ReadCloser, error) { | |||||
| input := &obs.GetObjectInput{} | input := &obs.GetObjectInput{} | ||||
| input.Bucket = setting.Bucket | |||||
| input.Key = strings.TrimPrefix(path.Join(setting.BasePath, path.Join(uuid[0:1], uuid[1:2], uuid, fileName)), "/") | |||||
| // input.Key = strings.TrimPrefix(path.Join(setting.BasePath, path.Join(uuid[0:1], uuid[1:2], uuid)), "/") | |||||
| input.Bucket = bucket | |||||
| input.Key = key | |||||
| output, err := ObsCli.GetObject(input) | output, err := ObsCli.GetObject(input) | ||||
| if err == nil { | if err == nil { | ||||
| log.Info("StorageClass:%s, ETag:%s, ContentType:%s, ContentLength:%d, LastModified:%s\n", | log.Info("StorageClass:%s, ETag:%s, ContentType:%s, ContentLength:%d, LastModified:%s\n", | ||||
| @@ -158,6 +199,11 @@ func ObsDownload(uuid string, fileName string) (io.ReadCloser, error) { | |||||
| } | } | ||||
| } | } | ||||
| func ObsDownload(uuid string, fileName string) (io.ReadCloser, error) { | |||||
| return ObsDownloadAFile(setting.Bucket, strings.TrimPrefix(path.Join(setting.BasePath, path.Join(uuid[0:1], uuid[1:2], uuid, fileName)), "/")) | |||||
| } | |||||
| func ObsModelDownload(JobName string, fileName string) (io.ReadCloser, error) { | func ObsModelDownload(JobName string, fileName string) (io.ReadCloser, error) { | ||||
| input := &obs.GetObjectInput{} | input := &obs.GetObjectInput{} | ||||
| input.Bucket = setting.Bucket | input.Bucket = setting.Bucket | ||||
| @@ -176,6 +222,160 @@ func ObsModelDownload(JobName string, fileName string) (io.ReadCloser, error) { | |||||
| } | } | ||||
| } | } | ||||
| func ObsCopyManyFile(srcBucket string, srcPath string, destBucket string, destPath string) (int64, error) { | |||||
| input := &obs.ListObjectsInput{} | |||||
| input.Bucket = srcBucket | |||||
| // 设置每页100个对象 | |||||
| input.MaxKeys = 100 | |||||
| input.Prefix = srcPath | |||||
| index := 1 | |||||
| length := len(srcPath) | |||||
| var fileTotalSize int64 | |||||
| log.Info("prefix=" + input.Prefix) | |||||
| for { | |||||
| output, err := ObsCli.ListObjects(input) | |||||
| if err == nil { | |||||
| log.Info("Page:%d\n", index) | |||||
| index++ | |||||
| for _, val := range output.Contents { | |||||
| destKey := destPath + val.Key[length:] | |||||
| obsCopyFile(srcBucket, val.Key, destBucket, destKey) | |||||
| fileTotalSize += val.Size | |||||
| } | |||||
| if output.IsTruncated { | |||||
| input.Marker = output.NextMarker | |||||
| } else { | |||||
| break | |||||
| } | |||||
| } else { | |||||
| if obsError, ok := err.(obs.ObsError); ok { | |||||
| log.Info("Code:%s\n", obsError.Code) | |||||
| log.Info("Message:%s\n", obsError.Message) | |||||
| } | |||||
| return 0, err | |||||
| } | |||||
| } | |||||
| return fileTotalSize, nil | |||||
| } | |||||
| func obsCopyFile(srcBucket string, srcKeyName string, destBucket string, destKeyName string) error { | |||||
| input := &obs.CopyObjectInput{} | |||||
| input.Bucket = destBucket | |||||
| input.Key = destKeyName | |||||
| input.CopySourceBucket = srcBucket | |||||
| input.CopySourceKey = srcKeyName | |||||
| _, err := ObsCli.CopyObject(input) | |||||
| if err == nil { | |||||
| log.Info("copy success,destBuckName:%s, destkeyname:%s", destBucket, destKeyName) | |||||
| } else { | |||||
| log.Info("copy failed,,destBuckName:%s, destkeyname:%s", destBucket, destKeyName) | |||||
| if obsError, ok := err.(obs.ObsError); ok { | |||||
| log.Info(obsError.Code) | |||||
| log.Info(obsError.Message) | |||||
| } | |||||
| return err | |||||
| } | |||||
| return nil | |||||
| } | |||||
| func GetOneLevelAllObjectUnderDir(bucket string, prefixRootPath string, relativePath string) ([]FileInfo, error) { | |||||
| input := &obs.ListObjectsInput{} | |||||
| input.Bucket = bucket | |||||
| input.Prefix = prefixRootPath + relativePath | |||||
| if !strings.HasSuffix(input.Prefix, "/") { | |||||
| input.Prefix += "/" | |||||
| } | |||||
| output, err := ObsCli.ListObjects(input) | |||||
| fileInfos := make([]FileInfo, 0) | |||||
| prefixLen := len(input.Prefix) | |||||
| if err == nil { | |||||
| for _, val := range output.Contents { | |||||
| log.Info("val key=" + val.Key) | |||||
| var isDir bool | |||||
| var fileName string | |||||
| if val.Key == input.Prefix { | |||||
| continue | |||||
| } | |||||
| if strings.Contains(val.Key[prefixLen:len(val.Key)-1], "/") { | |||||
| continue | |||||
| } | |||||
| if strings.HasSuffix(val.Key, "/") { | |||||
| isDir = true | |||||
| fileName = val.Key[prefixLen : len(val.Key)-1] | |||||
| relativePath += val.Key[prefixLen:] | |||||
| } else { | |||||
| isDir = false | |||||
| fileName = val.Key[prefixLen:] | |||||
| } | |||||
| fileInfo := FileInfo{ | |||||
| ModTime: val.LastModified.Local().Format("2006-01-02 15:04:05"), | |||||
| FileName: fileName, | |||||
| Size: val.Size, | |||||
| IsDir: isDir, | |||||
| ParenDir: relativePath, | |||||
| } | |||||
| fileInfos = append(fileInfos, fileInfo) | |||||
| } | |||||
| return fileInfos, err | |||||
| } else { | |||||
| if obsError, ok := err.(obs.ObsError); ok { | |||||
| log.Error("Code:%s, Message:%s", obsError.Code, obsError.Message) | |||||
| } | |||||
| return nil, err | |||||
| } | |||||
| } | |||||
| func GetAllObjectByBucketAndPrefix(bucket string, prefix string) ([]FileInfo, error) { | |||||
| input := &obs.ListObjectsInput{} | |||||
| input.Bucket = bucket | |||||
| // 设置每页100个对象 | |||||
| input.MaxKeys = 100 | |||||
| input.Prefix = prefix | |||||
| index := 1 | |||||
| fileInfos := make([]FileInfo, 0) | |||||
| prefixLen := len(prefix) | |||||
| log.Info("prefix=" + input.Prefix) | |||||
| for { | |||||
| output, err := ObsCli.ListObjects(input) | |||||
| if err == nil { | |||||
| log.Info("Page:%d\n", index) | |||||
| index++ | |||||
| for _, val := range output.Contents { | |||||
| var isDir bool | |||||
| if prefixLen == len(val.Key) { | |||||
| continue | |||||
| } | |||||
| if strings.HasSuffix(val.Key, "/") { | |||||
| isDir = true | |||||
| } else { | |||||
| isDir = false | |||||
| } | |||||
| fileInfo := FileInfo{ | |||||
| ModTime: val.LastModified.Format("2006-01-02 15:04:05"), | |||||
| FileName: val.Key[prefixLen:], | |||||
| Size: val.Size, | |||||
| IsDir: isDir, | |||||
| ParenDir: "", | |||||
| } | |||||
| fileInfos = append(fileInfos, fileInfo) | |||||
| } | |||||
| if output.IsTruncated { | |||||
| input.Marker = output.NextMarker | |||||
| } else { | |||||
| break | |||||
| } | |||||
| } else { | |||||
| if obsError, ok := err.(obs.ObsError); ok { | |||||
| log.Info("Code:%s\n", obsError.Code) | |||||
| log.Info("Message:%s\n", obsError.Message) | |||||
| } | |||||
| return nil, err | |||||
| } | |||||
| } | |||||
| return fileInfos, nil | |||||
| } | |||||
| func GetObsListObject(jobName, parentDir, versionName string) ([]FileInfo, error) { | func GetObsListObject(jobName, parentDir, versionName string) ([]FileInfo, error) { | ||||
| input := &obs.ListObjectsInput{} | input := &obs.ListObjectsInput{} | ||||
| input.Bucket = setting.Bucket | input.Bucket = setting.Bucket | ||||
| @@ -258,27 +458,6 @@ func ObsGenMultiPartSignedUrl(uuid string, uploadId string, partNumber int, file | |||||
| return output.SignedUrl, nil | return output.SignedUrl, nil | ||||
| } | } | ||||
| func GetObsCreateSignedUrl(jobName, parentDir, fileName string) (string, error) { | |||||
| input := &obs.CreateSignedUrlInput{} | |||||
| input.Bucket = setting.Bucket | |||||
| input.Key = strings.TrimPrefix(path.Join(setting.TrainJobModelPath, jobName, setting.OutPutPath, parentDir, fileName), "/") | |||||
| input.Expires = 60 * 60 | |||||
| input.Method = obs.HttpMethodGet | |||||
| reqParams := make(map[string]string) | |||||
| fileName = url.QueryEscape(fileName) | |||||
| reqParams["response-content-disposition"] = "attachment; filename=\"" + fileName + "\"" | |||||
| input.QueryParams = reqParams | |||||
| output, err := ObsCli.CreateSignedUrl(input) | |||||
| if err != nil { | |||||
| log.Error("CreateSignedUrl failed:", err.Error()) | |||||
| return "", err | |||||
| } | |||||
| log.Info("SignedUrl:%s", output.SignedUrl) | |||||
| return output.SignedUrl, nil | |||||
| } | |||||
| func GetObsCreateSignedUrlByBucketAndKey(bucket, key string) (string, error) { | func GetObsCreateSignedUrlByBucketAndKey(bucket, key string) (string, error) { | ||||
| input := &obs.CreateSignedUrlInput{} | input := &obs.CreateSignedUrlInput{} | ||||
| input.Bucket = bucket | input.Bucket = bucket | ||||
| @@ -302,7 +481,10 @@ func GetObsCreateSignedUrlByBucketAndKey(bucket, key string) (string, error) { | |||||
| } | } | ||||
| return output.SignedUrl, nil | return output.SignedUrl, nil | ||||
| } | |||||
| func GetObsCreateSignedUrl(jobName, parentDir, fileName string) (string, error) { | |||||
| return GetObsCreateSignedUrlByBucketAndKey(setting.Bucket, strings.TrimPrefix(path.Join(setting.TrainJobModelPath, jobName, setting.OutPutPath, parentDir, fileName), "/")) | |||||
| } | } | ||||
| func ObsGetPreSignedUrl(uuid, fileName string) (string, error) { | func ObsGetPreSignedUrl(uuid, fileName string) (string, error) { | ||||
| @@ -26,6 +26,7 @@ type ObjectStorage interface { | |||||
| PresignedGetURL(path string, fileName string) (string, error) | PresignedGetURL(path string, fileName string) (string, error) | ||||
| PresignedPutURL(path string) (string, error) | PresignedPutURL(path string) (string, error) | ||||
| HasObject(path string) (bool, error) | HasObject(path string) (bool, error) | ||||
| UploadObject(fileName, filePath string) error | |||||
| } | } | ||||
| // Copy copys a file from source ObjectStorage to dest ObjectStorage | // Copy copys a file from source ObjectStorage to dest ObjectStorage | ||||
| @@ -51,6 +52,7 @@ func Init() error { | |||||
| switch setting.Attachment.StoreType { | switch setting.Attachment.StoreType { | ||||
| case LocalStorageType: | case LocalStorageType: | ||||
| Attachments, err = NewLocalStorage(setting.Attachment.Path) | Attachments, err = NewLocalStorage(setting.Attachment.Path) | ||||
| log.Info("local storage inited.") | |||||
| case MinioStorageType: | case MinioStorageType: | ||||
| minio := setting.Attachment.Minio | minio := setting.Attachment.Minio | ||||
| Attachments, err = NewMinioStorage( | Attachments, err = NewMinioStorage( | ||||
| @@ -62,6 +64,7 @@ func Init() error { | |||||
| minio.BasePath, | minio.BasePath, | ||||
| minio.UseSSL, | minio.UseSSL, | ||||
| ) | ) | ||||
| log.Info("minio storage inited.") | |||||
| default: | default: | ||||
| return fmt.Errorf("Unsupported attachment store type: %s", setting.Attachment.StoreType) | return fmt.Errorf("Unsupported attachment store type: %s", setting.Attachment.StoreType) | ||||
| } | } | ||||
| @@ -71,6 +74,7 @@ func Init() error { | |||||
| log.Error("obs.New failed:", err) | log.Error("obs.New failed:", err) | ||||
| return err | return err | ||||
| } | } | ||||
| log.Info("obs cli inited.") | |||||
| if err != nil { | if err != nil { | ||||
| return err | return err | ||||
| @@ -816,6 +816,11 @@ get_repo_info_error=Can not get the information of the repository. | |||||
| generate_statistic_file_error=Fail to generate file. | generate_statistic_file_error=Fail to generate file. | ||||
| repo_stat_inspect=ProjectAnalysis | repo_stat_inspect=ProjectAnalysis | ||||
| all=All | all=All | ||||
| modelarts.status=Status | |||||
| modelarts.createtime=CreateTime | |||||
| modelarts.version_nums = Version Nums | |||||
| modelarts.version = Version | |||||
| modelarts.computing_resources=compute Resources | |||||
| modelarts.notebook=Debug Task | modelarts.notebook=Debug Task | ||||
| modelarts.train_job=Train Task | modelarts.train_job=Train Task | ||||
| modelarts.train_job.new_debug= New Debug Task | modelarts.train_job.new_debug= New Debug Task | ||||
| @@ -823,6 +828,10 @@ modelarts.train_job.new_train=New Train Task | |||||
| modelarts.train_job.config=Configuration information | modelarts.train_job.config=Configuration information | ||||
| modelarts.train_job.new=New train Task | modelarts.train_job.new=New train Task | ||||
| modelarts.train_job.new_place=The description should not exceed 256 characters | modelarts.train_job.new_place=The description should not exceed 256 characters | ||||
| modelarts.model_name=Model Name | |||||
| modelarts.model_size=Model Size | |||||
| modelarts.import_model=Import Model | |||||
| modelarts.modify=Modify | modelarts.modify=Modify | ||||
| modelarts.current_version=Current version | modelarts.current_version=Current version | ||||
| modelarts.parent_version=Parent Version | modelarts.parent_version=Parent Version | ||||
| @@ -874,6 +883,20 @@ modelarts.train_job_para_admin=train_job_para_admin | |||||
| modelarts.train_job_para.edit=train_job_para.edit | modelarts.train_job_para.edit=train_job_para.edit | ||||
| modelarts.train_job_para.connfirm=train_job_para.connfirm | modelarts.train_job_para.connfirm=train_job_para.connfirm | ||||
| model.manage.import_new_model=Import New Model | |||||
| model.manage.create_error=Equal Name and Version has existed. | |||||
| model.manage.model_name = Model Name | |||||
| model.manage.version = Version | |||||
| model.manage.label = Label | |||||
| model.manage.size = Size | |||||
| model.manage.create_time = Create Time | |||||
| model.manage.Description = Description | |||||
| model.manage.Accuracy = Accuracy | |||||
| model.manage.F1 = F1 | |||||
| model.manage.Precision = Precision | |||||
| model.manage.Recall = Recall | |||||
| model.manage.sava_model = Sava Model | |||||
| template.items = Template Items | template.items = Template Items | ||||
| template.git_content = Git Content (Default Branch) | template.git_content = Git Content (Default Branch) | ||||
| template.git_hooks = Git Hooks | template.git_hooks = Git Hooks | ||||
| @@ -1552,6 +1575,7 @@ settings.external_wiki_url_error = The external wiki URL is not a valid URL. | |||||
| settings.external_wiki_url_desc = Visitors are redirected to the external wiki URL when clicking the wiki tab. | settings.external_wiki_url_desc = Visitors are redirected to the external wiki URL when clicking the wiki tab. | ||||
| settings.dataset_desc = Enable Repository Dataset | settings.dataset_desc = Enable Repository Dataset | ||||
| settings.cloudbrain_desc = Enable Cloudbarin | settings.cloudbrain_desc = Enable Cloudbarin | ||||
| settings.model_desc = Enable Model Manage | |||||
| settings.issues_desc = Enable Repository Issue Tracker | settings.issues_desc = Enable Repository Issue Tracker | ||||
| settings.use_internal_issue_tracker = Use Built-In Issue Tracker | settings.use_internal_issue_tracker = Use Built-In Issue Tracker | ||||
| settings.use_external_issue_tracker = Use External Issue Tracker | settings.use_external_issue_tracker = Use External Issue Tracker | ||||
| @@ -228,6 +228,7 @@ users=用户 | |||||
| organizations=组织 | organizations=组织 | ||||
| images = 云脑镜像 | images = 云脑镜像 | ||||
| search=搜索 | search=搜索 | ||||
| search_pro=搜项目 | |||||
| code=代码 | code=代码 | ||||
| data_analysis=数字看板(内测) | data_analysis=数字看板(内测) | ||||
| repo_no_results=未找到匹配的项目。 | repo_no_results=未找到匹配的项目。 | ||||
| @@ -781,6 +782,9 @@ datasets=数据集 | |||||
| datasets.desc=数据集功能 | datasets.desc=数据集功能 | ||||
| cloudbrain_helper=使用GPU/NPU资源,开启Notebook、模型训练任务等 | cloudbrain_helper=使用GPU/NPU资源,开启Notebook、模型训练任务等 | ||||
| model_manager = 模型 | |||||
| model_noright=无权限操作 | |||||
| debug=调试 | debug=调试 | ||||
| stop=停止 | stop=停止 | ||||
| delete=删除 | delete=删除 | ||||
| @@ -823,6 +827,7 @@ all=所有 | |||||
| modelarts.status=状态 | modelarts.status=状态 | ||||
| modelarts.createtime=创建时间 | modelarts.createtime=创建时间 | ||||
| modelarts.version_nums=版本数 | modelarts.version_nums=版本数 | ||||
| modelarts.version=版本 | |||||
| modelarts.computing_resources=计算资源 | modelarts.computing_resources=计算资源 | ||||
| modelarts.notebook=调试任务 | modelarts.notebook=调试任务 | ||||
| modelarts.train_job=训练任务 | modelarts.train_job=训练任务 | ||||
| @@ -830,7 +835,11 @@ modelarts.train_job.new_debug=新建调试任务 | |||||
| modelarts.train_job.new_train=新建训练任务 | modelarts.train_job.new_train=新建训练任务 | ||||
| modelarts.train_job.config=配置信息 | modelarts.train_job.config=配置信息 | ||||
| modelarts.train_job.new=新建训练任务 | modelarts.train_job.new=新建训练任务 | ||||
| modelarts.train_job.new_place=描述字数不超过255个字符 | |||||
| modelarts.train_job.new_place=描述字数不超过256个字符 | |||||
| modelarts.model_name=模型名称 | |||||
| modelarts.model_size=模型大小 | |||||
| modelarts.import_model=导入模型 | |||||
| modelarts.train_job.label_place=输入标签,多个标签用空格区分 | |||||
| modelarts.modify=修改 | modelarts.modify=修改 | ||||
| modelarts.current_version=当前版本 | modelarts.current_version=当前版本 | ||||
| modelarts.parent_version=父版本 | modelarts.parent_version=父版本 | ||||
| @@ -848,7 +857,7 @@ modelarts.train_job.description=任务描述 | |||||
| modelarts.train_job.parameter_setting=参数设置 | modelarts.train_job.parameter_setting=参数设置 | ||||
| modelarts.train_job.parameter_setting_info=参数信息 | modelarts.train_job.parameter_setting_info=参数信息 | ||||
| modelarts.train_job.fast_parameter_setting=一键式参数配置 | modelarts.train_job.fast_parameter_setting=一键式参数配置 | ||||
| modelarts.train_job.fast_parameter_setting_config=如您已保存过参数配置,可单击 | |||||
| modelarts.train_job.fast_parameter_setting_config=如您已保存过参数配置,可单击 | |||||
| modelarts.train_job.fast_parameter_setting_config_link=这里 | modelarts.train_job.fast_parameter_setting_config_link=这里 | ||||
| modelarts.train_job.frames=常用框架 | modelarts.train_job.frames=常用框架 | ||||
| modelarts.train_job.algorithm_origin=算法来源 | modelarts.train_job.algorithm_origin=算法来源 | ||||
| @@ -886,6 +895,19 @@ modelarts.train_job_para_admin=任务参数管理 | |||||
| modelarts.train_job_para.edit=编辑 | modelarts.train_job_para.edit=编辑 | ||||
| modelarts.train_job_para.connfirm=确定 | modelarts.train_job_para.connfirm=确定 | ||||
| model.manage.import_new_model=导入新模型 | |||||
| model.manage.create_error=相同的名称和版本的模型已经存在。 | |||||
| model.manage.model_name = 模型名称 | |||||
| model.manage.version = 版本 | |||||
| model.manage.label = 标签 | |||||
| model.manage.size = 大小 | |||||
| model.manage.create_time = 创建时间 | |||||
| model.manage.description = 描述 | |||||
| model.manage.Accuracy = 准确率 | |||||
| model.manage.F1 = F1值 | |||||
| model.manage.Precision = 精确率 | |||||
| model.manage.Recall = 召回率 | |||||
| model.manage.sava_model = 保存模型 | |||||
| template.items=模板选项 | template.items=模板选项 | ||||
| template.git_content=Git数据(默认分支) | template.git_content=Git数据(默认分支) | ||||
| @@ -1565,6 +1587,7 @@ settings.external_wiki_url_error=外部百科链接无效 | |||||
| settings.external_wiki_url_desc=当点击任务标签时,访问者将被重定向到外部任务系统的URL。 | settings.external_wiki_url_desc=当点击任务标签时,访问者将被重定向到外部任务系统的URL。 | ||||
| settings.dataset_desc=启用数据集 | settings.dataset_desc=启用数据集 | ||||
| settings.cloudbrain_desc = 启用云脑 | settings.cloudbrain_desc = 启用云脑 | ||||
| settings.model_desc = 启用模型管理 | |||||
| settings.issues_desc=启用任务系统 | settings.issues_desc=启用任务系统 | ||||
| settings.use_internal_issue_tracker=使用内置的轻量级任务管理系统 | settings.use_internal_issue_tracker=使用内置的轻量级任务管理系统 | ||||
| settings.use_external_issue_tracker=使用外部的任务管理系统 | settings.use_external_issue_tracker=使用外部的任务管理系统 | ||||
| @@ -1965,7 +1988,7 @@ team_unit_desc=允许访问项目单元 | |||||
| team_unit_disabled=(已禁用) | team_unit_disabled=(已禁用) | ||||
| form.name_reserved=组织名称 '%s' 是被保留的。 | form.name_reserved=组织名称 '%s' 是被保留的。 | ||||
| form.name_pattern_not_allowed=项目名称中不允许使用 "%s"。 | |||||
| form.name_pattern_not_allowed=组织名称中不允许使用 "%s"。 | |||||
| form.create_org_not_allowed=此账号禁止创建组织 | form.create_org_not_allowed=此账号禁止创建组织 | ||||
| settings=组织设置 | settings=组织设置 | ||||
| @@ -0,0 +1 @@ | |||||
| <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="120" height="120"><path fill="none" d="M0 0h24v24H0z"/><path d="M20 22h-2v-2a3 3 0 0 0-3-3H9a3 3 0 0 0-3 3v2H4v-2a5 5 0 0 1 5-5h6a5 5 0 0 1 5 5v2zm-8-9a6 6 0 1 1 0-12 6 6 0 0 1 0 12zm0-2a4 4 0 1 0 0-8 4 4 0 0 0 0 8z" fill="rgba(0,0,0,0.4)"/></svg> | |||||
| @@ -0,0 +1 @@ | |||||
| <?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1638325192035" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2222" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M979.792374 404.577188 574.183101 83.942886c-34.918864-27.694272-89.619352-27.694272-124.538216 0L44.207626 404.577188c-13.933143 11.008903-16.169326 31.134554-5.332437 44.895683s30.618512 16.169326 44.551655 5.332437l12.55703-10.320847 0 387.547791c0 54.872501 57.968755 95.983874 108.712918 95.983874l639.892491 0c50.22812 0 83.254829-38.531161 83.254829-95.983874L927.844112 445.860575l11.69696 8.944734c5.84848 4.644381 13.073072 6.880564 20.125651 6.880564 9.460776 0 18.921552-4.128339 25.286074-12.213002C995.9617 435.711742 993.725517 415.586091 979.792374 404.577188zM479.919368 864.026877 479.919368 686.508315c0-8.77272 15.997312-13.245087 31.994625-13.245087s31.994625 4.472367 31.994625 13.245087l0 177.346548L479.919368 864.026877 479.919368 864.026877zM864.026877 832.032253c0 21.157736-5.84848 31.994625-19.26558 31.994625L608.585923 864.026877c0-0.516042-0.688056-0.860071-0.688056-1.376113L607.897867 686.508315c0-37.155048-29.930455-77.234336-95.983874-77.234336s-95.983874 40.079288-95.983874 77.234336l0 176.142449c0 0.516042 0.860071 0.860071 0.860071 1.376113L204.868806 864.026877c-20.125651 0-44.723669-17.373425-44.723669-31.994625L160.145137 393.740299 488.864102 134.171006c11.868974-9.288762 33.198723-9.288762 44.895683 0l330.095078 261.11742L863.854863 832.032253z" p-id="2223" fill="#1684FC"></path></svg> | |||||
| @@ -0,0 +1 @@ | |||||
| <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="120" height="120"><path fill="none" d="M0 0h24v24H0z"/><path d="M20 3l2 4v13a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V7.004L4 3h16zm0 6H4v10h16V9zm-8 1l4 4h-3v4h-2v-4H8l4-4zm6.764-5H5.236l-.999 2h15.527l-1-2z" fill="rgba(0,0,0,0.4)"/></svg> | |||||
| @@ -0,0 +1 @@ | |||||
| <?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1638171446718" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2430" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M512 69.717333l383.018667 221.141334v442.282666L512 954.282667 128.981333 733.141333V290.858667L512 69.717333zM192.96 375.402667v320.768L480 861.888V541.141333l-287.04-165.76z m638.058667 0L544 541.162667V861.866667l287.018667-165.717334V375.424zM512 143.637333L215.722667 314.666667 512 485.717333l296.256-171.050666L512 143.616z" fill="#1684FC" p-id="2431"></path></svg> | |||||
| @@ -0,0 +1 @@ | |||||
| <?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1638433773401" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2884" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M469.333333 768c-166.4 0-298.666667-132.266667-298.666666-298.666667s132.266667-298.666667 298.666666-298.666666 298.666667 132.266667 298.666667 298.666666-132.266667 298.666667-298.666667 298.666667z m0-85.333333c119.466667 0 213.333333-93.866667 213.333334-213.333334s-93.866667-213.333333-213.333334-213.333333-213.333333 93.866667-213.333333 213.333333 93.866667 213.333333 213.333333 213.333334z m251.733334 0l119.466666 119.466666-59.733333 59.733334-119.466667-119.466667 59.733334-59.733333z" fill="#5BB973" p-id="2885"></path></svg> | |||||
| @@ -0,0 +1 @@ | |||||
| <?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1638171175505" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2087" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M947.924 963.76c0 21.752-17.62 39.372-39.354 39.372-21.75 0-39.37-17.62-39.37-39.371l-0.354-3.655c0-1.554 0.283-3.054 0.442-4.59-24.576-172.792-172.72-299.768-353.104-301.763-1.447 0.036-2.825 0.23-4.29 0.23-1.43 0-2.807-0.194-4.237-0.23C329.34 655.731 182.607 779.9 155.56 949.69c0.9 3.337 1.536 6.78 1.536 10.4l0.37 3.707c0 22.086-17.902 39.989-39.97 39.989s-39.99-17.903-39.99-39.99l-0.035-0.352h-0.76c0.107-1.165 0.336-2.278 0.46-3.425 0-3.302 0.53-6.427 1.27-9.499C98.94 791.217 205.684 662.422 350.968 606.95c-84.586-54.2-139.74-149.963-139.74-259.372 0-169.224 131.478-306.405 300.702-306.405 169.208 0 300.703 137.18 300.703 306.405 0 109.374-55.102 205.118-139.652 259.32 144.278 55.03 250.544 182.325 272.19 340.038 1.465 4.131 2.436 8.528 2.436 13.17l0.318 3.656z m-204.43-616.094c0-127.947-103.706-231.654-231.653-231.654S280.188 219.736 280.188 347.666c0 127.929 103.724 231.636 231.653 231.636s231.654-103.707 231.654-231.636z" fill="#1684FC" p-id="2088"></path></svg> | |||||
| @@ -75,6 +75,7 @@ import ( | |||||
| "code.gitea.io/gitea/routers/api/v1/repo" | "code.gitea.io/gitea/routers/api/v1/repo" | ||||
| _ "code.gitea.io/gitea/routers/api/v1/swagger" // for swagger generation | _ "code.gitea.io/gitea/routers/api/v1/swagger" // for swagger generation | ||||
| "code.gitea.io/gitea/routers/api/v1/user" | "code.gitea.io/gitea/routers/api/v1/user" | ||||
| repo_ext "code.gitea.io/gitea/routers/repo" | |||||
| "gitea.com/macaron/binding" | "gitea.com/macaron/binding" | ||||
| "gitea.com/macaron/macaron" | "gitea.com/macaron/macaron" | ||||
| @@ -523,23 +524,26 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
| Get(notify.GetThread). | Get(notify.GetThread). | ||||
| Patch(notify.ReadThread) | Patch(notify.ReadThread) | ||||
| }, reqToken()) | }, reqToken()) | ||||
| adminReq := context.Toggle(&context.ToggleOptions{SignInRequired: true, AdminRequired: true}) | |||||
| operationReq := context.Toggle(&context.ToggleOptions{SignInRequired: true, OperationRequired: true}) | |||||
| //Project board | //Project board | ||||
| m.Group("/projectboard", func() { | m.Group("/projectboard", func() { | ||||
| m.Get("/restoreFork", adminReq, repo.RestoreForkNumber) | |||||
| m.Get("/downloadAll", adminReq, repo.ServeAllProjectsPeriodStatisticsFile) | |||||
| m.Get("/downloadAllOpenI", adminReq, repo.ServeAllProjectsOpenIStatisticsFile) | |||||
| m.Get("/restoreFork", repo.RestoreForkNumber) | |||||
| m.Get("/downloadAll", repo.ServeAllProjectsPeriodStatisticsFile) | |||||
| m.Get("/downloadAllOpenI", repo.ServeAllProjectsOpenIStatisticsFile) | |||||
| m.Group("/project", func() { | m.Group("/project", func() { | ||||
| m.Get("", adminReq, repo.GetAllProjectsPeriodStatistics) | |||||
| m.Get("", repo.GetAllProjectsPeriodStatistics) | |||||
| m.Group("/:id", func() { | m.Group("/:id", func() { | ||||
| m.Get("", adminReq, repo.GetProjectLatestStatistics) | |||||
| m.Get("/period", adminReq, repo.GetProjectPeriodStatistics) | |||||
| m.Get("", repo.GetProjectLatestStatistics) | |||||
| m.Get("/period", repo.GetProjectPeriodStatistics) | |||||
| }) | }) | ||||
| }) | }) | ||||
| }) | |||||
| }, operationReq) | |||||
| m.Get("/query_user_static_page", operationReq, repo_ext.QueryUserStaticDataPage) | |||||
| // Users | // Users | ||||
| m.Group("/users", func() { | m.Group("/users", func() { | ||||
| @@ -240,26 +240,28 @@ func DelTrainJobVersion(ctx *context.APIContext) { | |||||
| ctx.ServerError("get VersionListCount faild", err) | ctx.ServerError("get VersionListCount faild", err) | ||||
| return | return | ||||
| } | } | ||||
| // 判断当前删掉的任务是否是最新版本,若是,将排序后的TotalVersionCount置为删掉的最新版本的TotalVersionCount,若不是,按时间排序后的版本列表的第一个版本设置为最新版本,TotalVersionCount不变 | |||||
| if task.IsLatestVersion == modelarts.IsLatestVersion { | |||||
| err = models.SetVersionCountAndLatestVersion(jobID, VersionTaskList[0].Cloudbrain.VersionName, VersionListCount, modelarts.IsLatestVersion, task.TotalVersionCount) | |||||
| if err != nil { | |||||
| ctx.ServerError("UpdateJobVersionCount failed", err) | |||||
| return | |||||
| } | |||||
| } else { | |||||
| err = models.SetVersionCountAndLatestVersion(jobID, VersionTaskList[0].VersionName, VersionListCount, modelarts.IsLatestVersion, VersionTaskList[0].Cloudbrain.TotalVersionCount) | |||||
| if err != nil { | |||||
| ctx.ServerError("UpdateJobVersionCount failed", err) | |||||
| return | |||||
| if VersionListCount > 0 { | |||||
| // 判断当前删掉的任务是否是最新版本,若是,将排序后的TotalVersionCount置为删掉的最新版本的TotalVersionCount,若不是,按时间排序后的版本列表的第一个版本设置为最新版本,TotalVersionCount不变 | |||||
| if task.IsLatestVersion == modelarts.IsLatestVersion { | |||||
| err = models.SetVersionCountAndLatestVersion(jobID, VersionTaskList[0].Cloudbrain.VersionName, VersionListCount, modelarts.IsLatestVersion, task.TotalVersionCount) | |||||
| if err != nil { | |||||
| ctx.ServerError("UpdateJobVersionCount failed", err) | |||||
| return | |||||
| } | |||||
| } else { | |||||
| err = models.SetVersionCountAndLatestVersion(jobID, VersionTaskList[0].VersionName, VersionListCount, modelarts.IsLatestVersion, VersionTaskList[0].Cloudbrain.TotalVersionCount) | |||||
| if err != nil { | |||||
| ctx.ServerError("UpdateJobVersionCount failed", err) | |||||
| return | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| ctx.JSON(http.StatusOK, map[string]interface{}{ | ctx.JSON(http.StatusOK, map[string]interface{}{ | ||||
| "JobID": jobID, | |||||
| "VersionName": versionName, | |||||
| "StatusOK": 0, | |||||
| "JobID": jobID, | |||||
| "VersionName": versionName, | |||||
| "StatusOK": 0, | |||||
| "VersionListCount": VersionListCount, | |||||
| }) | }) | ||||
| } | } | ||||
| @@ -5,6 +5,7 @@ import ( | |||||
| "net/http" | "net/http" | ||||
| "net/url" | "net/url" | ||||
| "strconv" | "strconv" | ||||
| "strings" | |||||
| "time" | "time" | ||||
| "github.com/360EntSecGroup-Skylar/excelize/v2" | "github.com/360EntSecGroup-Skylar/excelize/v2" | ||||
| @@ -467,7 +468,7 @@ func generateCountSql(beginTime time.Time, endTime time.Time, latestDate string, | |||||
| "(SELECT repo_id,name,is_private,radar_total from public.repo_statistic where date='" + latestDate + "') B" + | "(SELECT repo_id,name,is_private,radar_total from public.repo_statistic where date='" + latestDate + "') B" + | ||||
| " where A.repo_id=B.repo_id" | " where A.repo_id=B.repo_id" | ||||
| if q != "" { | if q != "" { | ||||
| countSql = countSql + " and B.name like '%" + q + "%'" | |||||
| countSql = countSql + " and LOWER(B.name) like '%" + strings.ToLower(q) + "%'" | |||||
| } | } | ||||
| return countSql | return countSql | ||||
| } | } | ||||
| @@ -488,7 +489,7 @@ func generateTypeAllSql(beginTime time.Time, endTime time.Time, latestDate strin | |||||
| " where A.repo_id=B.repo_id" | " where A.repo_id=B.repo_id" | ||||
| if q != "" { | if q != "" { | ||||
| sql = sql + " and name like '%" + q + "%'" | |||||
| sql = sql + " and LOWER(name) like '%" + strings.ToLower(q) + "%'" | |||||
| } | } | ||||
| sql = sql + " order by " + orderBy + " desc,repo_id" + " limit " + strconv.Itoa(pageSize) + " offset " + strconv.Itoa((page-1)*pageSize) | sql = sql + " order by " + orderBy + " desc,repo_id" + " limit " + strconv.Itoa(pageSize) + " offset " + strconv.Itoa((page-1)*pageSize) | ||||
| return sql | return sql | ||||
| @@ -511,7 +512,7 @@ func generatePageSql(beginTime time.Time, endTime time.Time, latestDate string, | |||||
| "(SELECT repo_id,name,owner_name,is_private,radar_total from public.repo_statistic where date='" + latestDate + "') B" + | "(SELECT repo_id,name,owner_name,is_private,radar_total from public.repo_statistic where date='" + latestDate + "') B" + | ||||
| " where A.repo_id=B.repo_id" | " where A.repo_id=B.repo_id" | ||||
| if q != "" { | if q != "" { | ||||
| sql = sql + " and B.name like '%" + q + "%'" | |||||
| sql = sql + " and LOWER(B.name) like '%" + strings.ToLower(q) + "%'" | |||||
| } | } | ||||
| sql = sql + " order by " + orderBy + " desc,A.repo_id" + " limit " + strconv.Itoa(pageSize) + " offset " + strconv.Itoa((page-1)*pageSize) | sql = sql + " order by " + orderBy + " desc,A.repo_id" + " limit " + strconv.Itoa(pageSize) + " offset " + strconv.Itoa((page-1)*pageSize) | ||||
| return sql | return sql | ||||
| @@ -7,6 +7,8 @@ package routers | |||||
| import ( | import ( | ||||
| "bytes" | "bytes" | ||||
| "fmt" | |||||
| "io/ioutil" | |||||
| "net/http" | "net/http" | ||||
| "strings" | "strings" | ||||
| @@ -511,3 +513,43 @@ func NotFound(ctx *context.Context) { | |||||
| ctx.Data["Title"] = "Page Not Found" | ctx.Data["Title"] = "Page Not Found" | ||||
| ctx.NotFound("home.NotFound", nil) | ctx.NotFound("home.NotFound", nil) | ||||
| } | } | ||||
| func RecommendOrgFromPromote(ctx *context.Context) { | |||||
| url := setting.RecommentRepoAddr + "organizations" | |||||
| recommendFromPromote(ctx, url) | |||||
| } | |||||
| func recommendFromPromote(ctx *context.Context, url string) { | |||||
| resp, err := http.Get(url) | |||||
| if err != nil { | |||||
| log.Info("Get organizations url error=" + err.Error()) | |||||
| ctx.ServerError("QueryTrainJobList:", err) | |||||
| return | |||||
| } | |||||
| bytes, err := ioutil.ReadAll(resp.Body) | |||||
| resp.Body.Close() | |||||
| if err != nil { | |||||
| log.Info("Get organizations url error=" + err.Error()) | |||||
| ctx.ServerError("QueryTrainJobList:", err) | |||||
| return | |||||
| } | |||||
| allLineStr := string(bytes) | |||||
| lines := strings.Split(allLineStr, "\n") | |||||
| result := make([]string, len(lines)) | |||||
| for i, line := range lines { | |||||
| tmpIndex := strings.Index(line, ".") | |||||
| log.Info("i=" + fmt.Sprint(i) + " line=" + line + " tmpIndex=" + fmt.Sprint(tmpIndex)) | |||||
| if tmpIndex == -1 { | |||||
| result[i] = strings.Trim(line, " ") | |||||
| } else { | |||||
| result[i] = strings.Trim(line[tmpIndex+1:], " ") | |||||
| } | |||||
| } | |||||
| ctx.JSON(http.StatusOK, result) | |||||
| } | |||||
| func RecommendRepoFromPromote(ctx *context.Context) { | |||||
| url := setting.RecommentRepoAddr + "projects" | |||||
| recommendFromPromote(ctx, url) | |||||
| } | |||||
| @@ -60,11 +60,17 @@ func NewServices() { | |||||
| if err := storage.Init(); err != nil { | if err := storage.Init(); err != nil { | ||||
| log.Fatal("storage init failed: %v", err) | log.Fatal("storage init failed: %v", err) | ||||
| } | } | ||||
| log.Info("storage init succeed.") | |||||
| mailer.NewContext() | mailer.NewContext() | ||||
| log.Info("mailer.NewContext() succeed.") | |||||
| _ = cache.NewContext() | _ = cache.NewContext() | ||||
| log.Info("cache.NewContext() succeed.") | |||||
| notification.NewContext() | notification.NewContext() | ||||
| log.Info("notification.NewContext() succeed.") | |||||
| decompression.NewContext() | decompression.NewContext() | ||||
| log.Info("decompression.NewContext() succeed.") | |||||
| labelmsg.Init() | labelmsg.Init() | ||||
| log.Info("labelmsg.Init() succeed.") | |||||
| } | } | ||||
| // In case of problems connecting to DB, retry connection. Eg, PGSQL in Docker Container on Synology | // In case of problems connecting to DB, retry connection. Eg, PGSQL in Docker Container on Synology | ||||
| @@ -539,7 +539,7 @@ func updateRepoCommitCnt(ctx *macaron.Context, repo *models.Repository) error { | |||||
| } | } | ||||
| defer gitRepo.Close() | defer gitRepo.Close() | ||||
| count, err := gitRepo.GetAllCommitsCount() | |||||
| count, err := gitRepo.GetHeadCommitsCount() | |||||
| if err != nil { | if err != nil { | ||||
| log.Error("GetAllCommitsCount failed:%v", err.Error(), ctx.Data["MsgID"]) | log.Error("GetAllCommitsCount failed:%v", err.Error(), ctx.Data["MsgID"]) | ||||
| return err | return err | ||||
| @@ -0,0 +1,571 @@ | |||||
| package repo | |||||
| import ( | |||||
| "archive/zip" | |||||
| "encoding/json" | |||||
| "errors" | |||||
| "fmt" | |||||
| "net/http" | |||||
| "path" | |||||
| "strings" | |||||
| "code.gitea.io/gitea/models" | |||||
| "code.gitea.io/gitea/modules/context" | |||||
| "code.gitea.io/gitea/modules/log" | |||||
| "code.gitea.io/gitea/modules/setting" | |||||
| "code.gitea.io/gitea/modules/storage" | |||||
| uuid "github.com/satori/go.uuid" | |||||
| ) | |||||
| const ( | |||||
| Model_prefix = "aimodels/" | |||||
| tplModelManageIndex = "repo/modelmanage/index" | |||||
| tplModelManageDownload = "repo/modelmanage/download" | |||||
| tplModelInfo = "repo/modelmanage/showinfo" | |||||
| MODEL_LATEST = 1 | |||||
| MODEL_NOT_LATEST = 0 | |||||
| ) | |||||
| func saveModelByParameters(jobId string, versionName string, name string, version string, label string, description string, ctx *context.Context) error { | |||||
| aiTask, err := models.GetCloudbrainByJobIDAndVersionName(jobId, versionName) | |||||
| if err != nil { | |||||
| log.Info("query task error." + err.Error()) | |||||
| return err | |||||
| } | |||||
| uuid := uuid.NewV4() | |||||
| id := uuid.String() | |||||
| modelPath := id | |||||
| var lastNewModelId string | |||||
| var modelSize int64 | |||||
| cloudType := models.TypeCloudBrainTwo | |||||
| log.Info("find task name:" + aiTask.JobName) | |||||
| aimodels := models.QueryModelByName(name, aiTask.RepoID) | |||||
| if len(aimodels) > 0 { | |||||
| for _, model := range aimodels { | |||||
| if model.Version == version { | |||||
| return errors.New(ctx.Tr("repo.model.manage.create_error")) | |||||
| } | |||||
| if model.New == MODEL_LATEST { | |||||
| lastNewModelId = model.ID | |||||
| } | |||||
| } | |||||
| } | |||||
| cloudType = aiTask.Type | |||||
| //download model zip //train type | |||||
| if cloudType == models.TypeCloudBrainTwo { | |||||
| modelPath, modelSize, err = downloadModelFromCloudBrainTwo(id, aiTask.JobName, "", aiTask.TrainUrl) | |||||
| if err != nil { | |||||
| log.Info("download model from CloudBrainTwo faild." + err.Error()) | |||||
| return err | |||||
| } | |||||
| } | |||||
| accuracy := make(map[string]string) | |||||
| accuracy["F1"] = "" | |||||
| accuracy["Recall"] = "" | |||||
| accuracy["Accuracy"] = "" | |||||
| accuracy["Precision"] = "" | |||||
| accuracyJson, _ := json.Marshal(accuracy) | |||||
| log.Info("accuracyJson=" + string(accuracyJson)) | |||||
| aiTaskJson, _ := json.Marshal(aiTask) | |||||
| model := &models.AiModelManage{ | |||||
| ID: id, | |||||
| Version: version, | |||||
| VersionCount: len(aimodels) + 1, | |||||
| Label: label, | |||||
| Name: name, | |||||
| Description: description, | |||||
| New: MODEL_LATEST, | |||||
| Type: cloudType, | |||||
| Path: modelPath, | |||||
| Size: modelSize, | |||||
| AttachmentId: aiTask.Uuid, | |||||
| RepoId: aiTask.RepoID, | |||||
| UserId: ctx.User.ID, | |||||
| CodeBranch: aiTask.BranchName, | |||||
| CodeCommitID: aiTask.CommitID, | |||||
| Engine: aiTask.EngineID, | |||||
| TrainTaskInfo: string(aiTaskJson), | |||||
| Accuracy: string(accuracyJson), | |||||
| } | |||||
| err = models.SaveModelToDb(model) | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| if len(lastNewModelId) > 0 { | |||||
| //udpate status and version count | |||||
| models.ModifyModelNewProperty(lastNewModelId, MODEL_NOT_LATEST, 0) | |||||
| } | |||||
| log.Info("save model end.") | |||||
| return nil | |||||
| } | |||||
| func SaveModel(ctx *context.Context) { | |||||
| log.Info("save model start.") | |||||
| JobId := ctx.Query("JobId") | |||||
| VersionName := ctx.Query("VersionName") | |||||
| name := ctx.Query("Name") | |||||
| version := ctx.Query("Version") | |||||
| label := ctx.Query("Label") | |||||
| description := ctx.Query("Description") | |||||
| if !ctx.Repo.CanWrite(models.UnitTypeModelManage) { | |||||
| ctx.ServerError("No right.", errors.New(ctx.Tr("repo.model_noright"))) | |||||
| return | |||||
| } | |||||
| if JobId == "" || VersionName == "" { | |||||
| ctx.Error(500, fmt.Sprintf("JobId or VersionName is null.")) | |||||
| return | |||||
| } | |||||
| if name == "" || version == "" { | |||||
| ctx.Error(500, fmt.Sprintf("name or version is null.")) | |||||
| return | |||||
| } | |||||
| err := saveModelByParameters(JobId, VersionName, name, version, label, description, ctx) | |||||
| if err != nil { | |||||
| log.Info("save model error." + err.Error()) | |||||
| ctx.Error(500, fmt.Sprintf("save model error. %v", err)) | |||||
| return | |||||
| } | |||||
| log.Info("save model end.") | |||||
| } | |||||
| func downloadModelFromCloudBrainTwo(modelUUID string, jobName string, parentDir string, trainUrl string) (string, int64, error) { | |||||
| objectkey := strings.TrimPrefix(path.Join(setting.TrainJobModelPath, jobName, setting.OutPutPath, parentDir), "/") | |||||
| if trainUrl != "" { | |||||
| objectkey = strings.Trim(trainUrl[len(setting.Bucket)+1:], "/") | |||||
| } | |||||
| modelDbResult, err := storage.GetOneLevelAllObjectUnderDir(setting.Bucket, objectkey, "") | |||||
| log.Info("bucket=" + setting.Bucket + " objectkey=" + objectkey) | |||||
| if err != nil { | |||||
| log.Info("get TrainJobListModel failed:", err) | |||||
| return "", 0, err | |||||
| } | |||||
| if len(modelDbResult) == 0 { | |||||
| return "", 0, errors.New("cannot create model, as model is empty.") | |||||
| } | |||||
| prefix := objectkey + "/" | |||||
| destKeyNamePrefix := Model_prefix + models.AttachmentRelativePath(modelUUID) + "/" | |||||
| size, err := storage.ObsCopyManyFile(setting.Bucket, prefix, setting.Bucket, destKeyNamePrefix) | |||||
| dataActualPath := setting.Bucket + "/" + destKeyNamePrefix | |||||
| return dataActualPath, size, nil | |||||
| } | |||||
| func DeleteModel(ctx *context.Context) { | |||||
| log.Info("delete model start.") | |||||
| id := ctx.Query("ID") | |||||
| err := deleteModelByID(ctx, id) | |||||
| if err != nil { | |||||
| ctx.JSON(500, err.Error()) | |||||
| } else { | |||||
| ctx.JSON(200, map[string]string{ | |||||
| "result_code": "0", | |||||
| }) | |||||
| } | |||||
| } | |||||
| func isCanDeleteOrDownload(ctx *context.Context, model *models.AiModelManage) bool { | |||||
| if ctx.User.IsAdmin || ctx.User.ID == model.UserId { | |||||
| return true | |||||
| } | |||||
| if ctx.Repo.IsOwner() { | |||||
| return true | |||||
| } | |||||
| return false | |||||
| } | |||||
| func deleteModelByID(ctx *context.Context, id string) error { | |||||
| log.Info("delete model start. id=" + id) | |||||
| model, err := models.QueryModelById(id) | |||||
| if !isCanDeleteOrDownload(ctx, model) { | |||||
| return errors.New(ctx.Tr("repo.model_noright")) | |||||
| } | |||||
| if err == nil { | |||||
| log.Info("bucket=" + setting.Bucket + " path=" + model.Path) | |||||
| if strings.HasPrefix(model.Path, setting.Bucket+"/"+Model_prefix) { | |||||
| err := storage.ObsRemoveObject(setting.Bucket, model.Path[len(setting.Bucket)+1:]) | |||||
| if err != nil { | |||||
| log.Info("Failed to delete model. id=" + id) | |||||
| return err | |||||
| } | |||||
| } | |||||
| err = models.DeleteModelById(id) | |||||
| if err == nil { //find a model to change new | |||||
| aimodels := models.QueryModelByName(model.Name, model.RepoId) | |||||
| if model.New == MODEL_LATEST { | |||||
| if len(aimodels) > 0 { | |||||
| //udpate status and version count | |||||
| models.ModifyModelNewProperty(aimodels[0].ID, MODEL_LATEST, len(aimodels)) | |||||
| } | |||||
| } else { | |||||
| for _, tmpModel := range aimodels { | |||||
| if tmpModel.New == MODEL_LATEST { | |||||
| models.ModifyModelNewProperty(tmpModel.ID, MODEL_LATEST, len(aimodels)) | |||||
| break | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| return err | |||||
| } | |||||
| func QueryModelByParameters(repoId int64, page int) ([]*models.AiModelManage, int64, error) { | |||||
| return models.QueryModel(&models.AiModelQueryOptions{ | |||||
| ListOptions: models.ListOptions{ | |||||
| Page: page, | |||||
| PageSize: setting.UI.IssuePagingNum, | |||||
| }, | |||||
| RepoID: repoId, | |||||
| Type: -1, | |||||
| New: MODEL_LATEST, | |||||
| }) | |||||
| } | |||||
| func DownloadMultiModelFile(ctx *context.Context) { | |||||
| log.Info("DownloadMultiModelFile start.") | |||||
| id := ctx.Query("ID") | |||||
| log.Info("id=" + id) | |||||
| task, err := models.QueryModelById(id) | |||||
| if err != nil { | |||||
| log.Error("no such model!", err.Error()) | |||||
| ctx.ServerError("no such model:", err) | |||||
| return | |||||
| } | |||||
| if !isCanDeleteOrDownload(ctx, task) { | |||||
| ctx.ServerError("no right.", errors.New(ctx.Tr("repo.model_noright"))) | |||||
| return | |||||
| } | |||||
| path := Model_prefix + models.AttachmentRelativePath(id) + "/" | |||||
| allFile, err := storage.GetAllObjectByBucketAndPrefix(setting.Bucket, path) | |||||
| if err == nil { | |||||
| //count++ | |||||
| models.ModifyModelDownloadCount(id) | |||||
| returnFileName := task.Name + "_" + task.Version + ".zip" | |||||
| ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+returnFileName) | |||||
| ctx.Resp.Header().Set("Content-Type", "application/octet-stream") | |||||
| w := zip.NewWriter(ctx.Resp) | |||||
| defer w.Close() | |||||
| for _, oneFile := range allFile { | |||||
| if oneFile.IsDir { | |||||
| log.Info("zip dir name:" + oneFile.FileName) | |||||
| } else { | |||||
| log.Info("zip file name:" + oneFile.FileName) | |||||
| fDest, err := w.Create(oneFile.FileName) | |||||
| if err != nil { | |||||
| log.Info("create zip entry error, download file failed: %s\n", err.Error()) | |||||
| ctx.ServerError("download file failed:", err) | |||||
| return | |||||
| } | |||||
| body, err := storage.ObsDownloadAFile(setting.Bucket, path+oneFile.FileName) | |||||
| if err != nil { | |||||
| log.Info("download file failed: %s\n", err.Error()) | |||||
| ctx.ServerError("download file failed:", err) | |||||
| return | |||||
| } else { | |||||
| defer body.Close() | |||||
| p := make([]byte, 1024) | |||||
| var readErr error | |||||
| var readCount int | |||||
| // 读取对象内容 | |||||
| for { | |||||
| readCount, readErr = body.Read(p) | |||||
| if readCount > 0 { | |||||
| fDest.Write(p[:readCount]) | |||||
| } | |||||
| if readErr != nil { | |||||
| break | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } else { | |||||
| log.Info("error,msg=" + err.Error()) | |||||
| ctx.ServerError("no file to download.", err) | |||||
| } | |||||
| } | |||||
| func QueryTrainJobVersionList(ctx *context.Context) { | |||||
| log.Info("query train job version list. start.") | |||||
| JobID := ctx.Query("JobID") | |||||
| VersionListTasks, count, err := models.QueryModelTrainJobVersionList(JobID) | |||||
| log.Info("query return count=" + fmt.Sprint(count)) | |||||
| if err != nil { | |||||
| ctx.ServerError("QueryTrainJobList:", err) | |||||
| } else { | |||||
| ctx.JSON(200, VersionListTasks) | |||||
| } | |||||
| } | |||||
| func QueryTrainJobList(ctx *context.Context) { | |||||
| log.Info("query train job list. start.") | |||||
| repoId := ctx.QueryInt64("repoId") | |||||
| VersionListTasks, count, err := models.QueryModelTrainJobList(repoId) | |||||
| log.Info("query return count=" + fmt.Sprint(count)) | |||||
| if err != nil { | |||||
| ctx.ServerError("QueryTrainJobList:", err) | |||||
| } else { | |||||
| ctx.JSON(200, VersionListTasks) | |||||
| } | |||||
| } | |||||
| func DownloadSingleModelFile(ctx *context.Context) { | |||||
| log.Info("DownloadSingleModelFile start.") | |||||
| id := ctx.Params(":ID") | |||||
| parentDir := ctx.Query("parentDir") | |||||
| fileName := ctx.Query("fileName") | |||||
| path := Model_prefix + models.AttachmentRelativePath(id) + "/" + parentDir + fileName | |||||
| if setting.PROXYURL != "" { | |||||
| body, err := storage.ObsDownloadAFile(setting.Bucket, path) | |||||
| if err != nil { | |||||
| log.Info("download error.") | |||||
| } else { | |||||
| //count++ | |||||
| models.ModifyModelDownloadCount(id) | |||||
| defer body.Close() | |||||
| ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+fileName) | |||||
| ctx.Resp.Header().Set("Content-Type", "application/octet-stream") | |||||
| p := make([]byte, 1024) | |||||
| var readErr error | |||||
| var readCount int | |||||
| // 读取对象内容 | |||||
| for { | |||||
| readCount, readErr = body.Read(p) | |||||
| if readCount > 0 { | |||||
| ctx.Resp.Write(p[:readCount]) | |||||
| //fmt.Printf("%s", p[:readCount]) | |||||
| } | |||||
| if readErr != nil { | |||||
| break | |||||
| } | |||||
| } | |||||
| } | |||||
| } else { | |||||
| url, err := storage.GetObsCreateSignedUrlByBucketAndKey(setting.Bucket, path) | |||||
| if err != nil { | |||||
| log.Error("GetObsCreateSignedUrl failed: %v", err.Error(), ctx.Data["msgID"]) | |||||
| ctx.ServerError("GetObsCreateSignedUrl", err) | |||||
| return | |||||
| } | |||||
| //count++ | |||||
| models.ModifyModelDownloadCount(id) | |||||
| http.Redirect(ctx.Resp, ctx.Req.Request, url, http.StatusMovedPermanently) | |||||
| } | |||||
| } | |||||
| func ShowModelInfo(ctx *context.Context) { | |||||
| ctx.Data["ID"] = ctx.Query("ID") | |||||
| ctx.Data["name"] = ctx.Query("name") | |||||
| ctx.Data["isModelManage"] = true | |||||
| ctx.HTML(200, tplModelInfo) | |||||
| } | |||||
| func ShowSingleModel(ctx *context.Context) { | |||||
| name := ctx.Query("name") | |||||
| log.Info("Show single ModelInfo start.name=" + name) | |||||
| models := models.QueryModelByName(name, ctx.Repo.Repository.ID) | |||||
| userIds := make([]int64, len(models)) | |||||
| for i, model := range models { | |||||
| model.IsCanOper = isOper(ctx, model.UserId) | |||||
| userIds[i] = model.UserId | |||||
| } | |||||
| userNameMap := queryUserName(userIds) | |||||
| for _, model := range models { | |||||
| value := userNameMap[model.UserId] | |||||
| if value != nil { | |||||
| model.UserName = value.Name | |||||
| model.UserRelAvatarLink = value.RelAvatarLink() | |||||
| } | |||||
| } | |||||
| ctx.JSON(http.StatusOK, models) | |||||
| } | |||||
| func queryUserName(intSlice []int64) map[int64]*models.User { | |||||
| keys := make(map[int64]string) | |||||
| uniqueElements := []int64{} | |||||
| for _, entry := range intSlice { | |||||
| if _, value := keys[entry]; !value { | |||||
| keys[entry] = "" | |||||
| uniqueElements = append(uniqueElements, entry) | |||||
| } | |||||
| } | |||||
| result := make(map[int64]*models.User) | |||||
| userLists, err := models.GetUsersByIDs(uniqueElements) | |||||
| if err == nil { | |||||
| for _, user := range userLists { | |||||
| result[user.ID] = user | |||||
| } | |||||
| } | |||||
| return result | |||||
| } | |||||
| func ShowOneVersionOtherModel(ctx *context.Context) { | |||||
| repoId := ctx.Repo.Repository.ID | |||||
| name := ctx.Query("name") | |||||
| aimodels := models.QueryModelByName(name, repoId) | |||||
| userIds := make([]int64, len(aimodels)) | |||||
| for i, model := range aimodels { | |||||
| model.IsCanOper = isOper(ctx, model.UserId) | |||||
| userIds[i] = model.UserId | |||||
| } | |||||
| userNameMap := queryUserName(userIds) | |||||
| for _, model := range aimodels { | |||||
| value := userNameMap[model.UserId] | |||||
| if value != nil { | |||||
| model.UserName = value.Name | |||||
| model.UserRelAvatarLink = value.RelAvatarLink() | |||||
| } | |||||
| } | |||||
| if len(aimodels) > 0 { | |||||
| ctx.JSON(200, aimodels[1:]) | |||||
| } else { | |||||
| ctx.JSON(200, aimodels) | |||||
| } | |||||
| } | |||||
| func ShowModelTemplate(ctx *context.Context) { | |||||
| ctx.Data["isModelManage"] = true | |||||
| ctx.HTML(200, tplModelManageIndex) | |||||
| } | |||||
| func isQueryRight(ctx *context.Context) bool { | |||||
| if ctx.Repo.Repository.IsPrivate { | |||||
| if ctx.Repo.CanRead(models.UnitTypeModelManage) || ctx.User.IsAdmin || ctx.Repo.IsAdmin() || ctx.Repo.IsOwner() { | |||||
| return true | |||||
| } | |||||
| return false | |||||
| } else { | |||||
| return true | |||||
| } | |||||
| } | |||||
| func isOper(ctx *context.Context, modelUserId int64) bool { | |||||
| if ctx.User == nil { | |||||
| return false | |||||
| } | |||||
| if ctx.User.IsAdmin || ctx.Repo.IsOwner() || ctx.User.ID == modelUserId { | |||||
| return true | |||||
| } | |||||
| return false | |||||
| } | |||||
| func ShowModelPageInfo(ctx *context.Context) { | |||||
| log.Info("ShowModelInfo start.") | |||||
| if !isQueryRight(ctx) { | |||||
| ctx.ServerError("no right.", errors.New(ctx.Tr("repo.model_noright"))) | |||||
| return | |||||
| } | |||||
| page := ctx.QueryInt("page") | |||||
| if page <= 0 { | |||||
| page = 1 | |||||
| } | |||||
| pageSize := ctx.QueryInt("pageSize") | |||||
| if pageSize <= 0 { | |||||
| pageSize = setting.UI.IssuePagingNum | |||||
| } | |||||
| repoId := ctx.Repo.Repository.ID | |||||
| Type := -1 | |||||
| modelResult, count, err := models.QueryModel(&models.AiModelQueryOptions{ | |||||
| ListOptions: models.ListOptions{ | |||||
| Page: page, | |||||
| PageSize: pageSize, | |||||
| }, | |||||
| RepoID: repoId, | |||||
| Type: Type, | |||||
| New: MODEL_LATEST, | |||||
| }) | |||||
| if err != nil { | |||||
| ctx.ServerError("Cloudbrain", err) | |||||
| return | |||||
| } | |||||
| userIds := make([]int64, len(modelResult)) | |||||
| for i, model := range modelResult { | |||||
| model.IsCanOper = isOper(ctx, model.UserId) | |||||
| userIds[i] = model.UserId | |||||
| } | |||||
| userNameMap := queryUserName(userIds) | |||||
| for _, model := range modelResult { | |||||
| value := userNameMap[model.UserId] | |||||
| if value != nil { | |||||
| model.UserName = value.Name | |||||
| model.UserRelAvatarLink = value.RelAvatarLink() | |||||
| } | |||||
| } | |||||
| mapInterface := make(map[string]interface{}) | |||||
| mapInterface["data"] = modelResult | |||||
| mapInterface["count"] = count | |||||
| ctx.JSON(http.StatusOK, mapInterface) | |||||
| } | |||||
| func ModifyModel(id string, description string) error { | |||||
| err := models.ModifyModelDescription(id, description) | |||||
| if err == nil { | |||||
| log.Info("modify success.") | |||||
| } else { | |||||
| log.Info("Failed to modify.id=" + id + " desc=" + description + " error:" + err.Error()) | |||||
| } | |||||
| return err | |||||
| } | |||||
| func ModifyModelInfo(ctx *context.Context) { | |||||
| log.Info("modify model start.") | |||||
| id := ctx.Query("ID") | |||||
| description := ctx.Query("Description") | |||||
| task, err := models.QueryModelById(id) | |||||
| if err != nil { | |||||
| log.Error("no such model!", err.Error()) | |||||
| ctx.ServerError("no such model:", err) | |||||
| return | |||||
| } | |||||
| if !isCanDeleteOrDownload(ctx, task) { | |||||
| ctx.ServerError("no right.", errors.New(ctx.Tr("repo.model_noright"))) | |||||
| return | |||||
| } | |||||
| err = ModifyModel(id, description) | |||||
| if err != nil { | |||||
| log.Info("modify error," + err.Error()) | |||||
| ctx.ServerError("error.", err) | |||||
| } else { | |||||
| ctx.JSON(200, "success") | |||||
| } | |||||
| } | |||||
| @@ -8,7 +8,6 @@ import ( | |||||
| "io" | "io" | ||||
| "net/http" | "net/http" | ||||
| "os" | "os" | ||||
| "os/exec" | |||||
| "regexp" | "regexp" | ||||
| "sort" | "sort" | ||||
| "strconv" | "strconv" | ||||
| @@ -50,46 +49,6 @@ func MustEnableCloudbrain(ctx *context.Context) { | |||||
| return | return | ||||
| } | } | ||||
| } | } | ||||
| func CloudBrainIndex(ctx *context.Context) { | |||||
| MustEnableCloudbrain(ctx) | |||||
| repo := ctx.Repo.Repository | |||||
| page := ctx.QueryInt("page") | |||||
| if page <= 0 { | |||||
| page = 1 | |||||
| } | |||||
| ciTasks, count, err := models.Cloudbrains(&models.CloudbrainsOptions{ | |||||
| ListOptions: models.ListOptions{ | |||||
| Page: page, | |||||
| PageSize: setting.UI.IssuePagingNum, | |||||
| }, | |||||
| RepoID: repo.ID, | |||||
| Type: models.TypeCloudBrainOne, | |||||
| }) | |||||
| if err != nil { | |||||
| ctx.ServerError("Cloudbrain", err) | |||||
| return | |||||
| } | |||||
| timestamp := time.Now().Unix() | |||||
| for i, task := range ciTasks { | |||||
| if task.Status == string(models.JobRunning) && (timestamp-int64(task.Cloudbrain.CreatedUnix) > 10) { | |||||
| ciTasks[i].CanDebug = true | |||||
| } else { | |||||
| ciTasks[i].CanDebug = false | |||||
| } | |||||
| ciTasks[i].CanDel = models.CanDelJob(ctx.IsSigned, ctx.User, task) | |||||
| } | |||||
| pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, 5) | |||||
| pager.SetDefaultParams(ctx) | |||||
| ctx.Data["Page"] = pager | |||||
| ctx.Data["PageIsCloudBrain"] = true | |||||
| ctx.Data["Tasks"] = ciTasks | |||||
| ctx.HTML(200, tplCloudBrainIndex) | |||||
| } | |||||
| func cutString(str string, lens int) string { | func cutString(str string, lens int) string { | ||||
| if len(str) < lens { | if len(str) < lens { | ||||
| @@ -247,14 +206,11 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { | |||||
| } | } | ||||
| repo := ctx.Repo.Repository | repo := ctx.Repo.Repository | ||||
| downloadCode(repo, codePath) | downloadCode(repo, codePath) | ||||
| uploadCodeToMinio(codePath+"/", jobName, "/code/") | |||||
| modelPath := setting.JobPath + jobName + cloudbrain.ModelMountPath | |||||
| err = os.MkdirAll(modelPath, os.ModePerm) | |||||
| if err != nil { | |||||
| cloudBrainNewDataPrepare(ctx) | |||||
| ctx.RenderWithErr(err.Error(), tplCloudBrainNew, &form) | |||||
| return | |||||
| } | |||||
| modelPath := setting.JobPath + jobName + cloudbrain.ModelMountPath + "/" | |||||
| mkModelPath(modelPath) | |||||
| uploadCodeToMinio(modelPath, jobName, cloudbrain.ModelMountPath+"/") | |||||
| benchmarkPath := setting.JobPath + jobName + cloudbrain.BenchMarkMountPath | benchmarkPath := setting.JobPath + jobName + cloudbrain.BenchMarkMountPath | ||||
| if setting.IsBenchmarkEnabled && jobType == string(models.JobTypeBenchmark) { | if setting.IsBenchmarkEnabled && jobType == string(models.JobTypeBenchmark) { | ||||
| @@ -264,26 +220,31 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { | |||||
| gpuType = gpuInfo.Value | gpuType = gpuInfo.Value | ||||
| } | } | ||||
| } | } | ||||
| downloadRateCode(repo, jobName, setting.BenchmarkCode, benchmarkPath, form.BenchmarkCategory, gpuType) | |||||
| downloadRateCode(repo, jobName, setting.BenchmarkOwner, setting.BrainScoreName, benchmarkPath, form.BenchmarkCategory, gpuType) | |||||
| uploadCodeToMinio(benchmarkPath+"/", jobName, cloudbrain.BenchMarkMountPath+"/") | |||||
| } | } | ||||
| snn4imagenetPath := setting.JobPath + jobName + cloudbrain.Snn4imagenetMountPath | snn4imagenetPath := setting.JobPath + jobName + cloudbrain.Snn4imagenetMountPath | ||||
| if setting.IsSnn4imagenetEnabled && jobType == string(models.JobTypeSnn4imagenet) { | if setting.IsSnn4imagenetEnabled && jobType == string(models.JobTypeSnn4imagenet) { | ||||
| downloadRateCode(repo, jobName, setting.Snn4imagenetCode, snn4imagenetPath, "", "") | |||||
| downloadRateCode(repo, jobName, setting.Snn4imagenetOwner, setting.Snn4imagenetName, snn4imagenetPath, "", "") | |||||
| uploadCodeToMinio(snn4imagenetPath+"/", jobName, cloudbrain.Snn4imagenetMountPath+"/") | |||||
| } | } | ||||
| brainScorePath := setting.JobPath + jobName + cloudbrain.BrainScoreMountPath | brainScorePath := setting.JobPath + jobName + cloudbrain.BrainScoreMountPath | ||||
| if setting.IsBrainScoreEnabled && jobType == string(models.JobTypeBrainScore) { | if setting.IsBrainScoreEnabled && jobType == string(models.JobTypeBrainScore) { | ||||
| downloadRateCode(repo, jobName, setting.BrainScoreCode, brainScorePath, "", "") | |||||
| downloadRateCode(repo, jobName, setting.BrainScoreOwner, setting.BrainScoreName, brainScorePath, "", "") | |||||
| uploadCodeToMinio(brainScorePath+"/", jobName, cloudbrain.BrainScoreMountPath+"/") | |||||
| } | } | ||||
| err = cloudbrain.GenerateTask(ctx, jobName, image, command, uuid, codePath, modelPath, benchmarkPath, snn4imagenetPath, brainScorePath, jobType, gpuQueue, resourceSpecId) | |||||
| err = cloudbrain.GenerateTask(ctx, jobName, image, command, uuid, codePath, getMinioPath(jobName, cloudbrain.ModelMountPath+"/"), | |||||
| getMinioPath(jobName, cloudbrain.BenchMarkMountPath+"/"), getMinioPath(jobName, cloudbrain.Snn4imagenetMountPath+"/"), | |||||
| getMinioPath(jobName, cloudbrain.BrainScoreMountPath+"/"), jobType, gpuQueue, resourceSpecId) | |||||
| if err != nil { | if err != nil { | ||||
| cloudBrainNewDataPrepare(ctx) | cloudBrainNewDataPrepare(ctx) | ||||
| ctx.RenderWithErr(err.Error(), tplCloudBrainNew, &form) | ctx.RenderWithErr(err.Error(), tplCloudBrainNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/cloudbrain") | |||||
| ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob") | |||||
| } | } | ||||
| func CloudBrainShow(ctx *context.Context) { | func CloudBrainShow(ctx *context.Context) { | ||||
| @@ -338,7 +299,7 @@ func CloudBrainDebug(ctx *context.Context) { | |||||
| var jobID = ctx.Params(":jobid") | var jobID = ctx.Params(":jobid") | ||||
| if !ctx.IsSigned { | if !ctx.IsSigned { | ||||
| log.Error("the user has not signed in") | log.Error("the user has not signed in") | ||||
| ctx.Error(http.StatusForbidden, "","the user has not signed in") | |||||
| ctx.Error(http.StatusForbidden, "", "the user has not signed in") | |||||
| return | return | ||||
| } | } | ||||
| task, err := models.GetCloudbrainByJobID(jobID) | task, err := models.GetCloudbrainByJobID(jobID) | ||||
| @@ -355,7 +316,7 @@ func CloudBrainCommitImage(ctx *context.Context, form auth.CommitImageCloudBrain | |||||
| var jobID = ctx.Params(":jobid") | var jobID = ctx.Params(":jobid") | ||||
| if !ctx.IsSigned { | if !ctx.IsSigned { | ||||
| log.Error("the user has not signed in") | log.Error("the user has not signed in") | ||||
| ctx.Error(http.StatusForbidden, "","the user has not signed in") | |||||
| ctx.Error(http.StatusForbidden, "", "the user has not signed in") | |||||
| return | return | ||||
| } | } | ||||
| task, err := models.GetCloudbrainByJobID(jobID) | task, err := models.GetCloudbrainByJobID(jobID) | ||||
| @@ -415,8 +376,7 @@ func CloudBrainStop(ctx *context.Context) { | |||||
| ctx.ServerError("UpdateJob failed", err) | ctx.ServerError("UpdateJob failed", err) | ||||
| return | return | ||||
| } | } | ||||
| ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/cloudbrain") | |||||
| ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob") | |||||
| } | } | ||||
| func StopJobsByUserID(userID int64) { | func StopJobsByUserID(userID int64) { | ||||
| @@ -452,14 +412,22 @@ func StopJobs(cloudBrains []*models.Cloudbrain) { | |||||
| logErrorAndUpdateJobStatus(err, taskInfo) | logErrorAndUpdateJobStatus(err, taskInfo) | ||||
| } else { | } else { | ||||
| param := models.NotebookAction{ | |||||
| Action: models.ActionStop, | |||||
| if taskInfo.JobType == string(models.JobTypeTrain) { | |||||
| err := retry(3, time.Second*30, func() error { | |||||
| _, err := modelarts.StopTrainJob(taskInfo.JobID, strconv.FormatInt(taskInfo.VersionID, 10)) | |||||
| return err | |||||
| }) | |||||
| logErrorAndUpdateJobStatus(err, taskInfo) | |||||
| } else { | |||||
| param := models.NotebookAction{ | |||||
| Action: models.ActionStop, | |||||
| } | |||||
| err := retry(3, time.Second*30, func() error { | |||||
| _, err := modelarts.StopJob(taskInfo.JobID, param) | |||||
| return err | |||||
| }) | |||||
| logErrorAndUpdateJobStatus(err, taskInfo) | |||||
| } | } | ||||
| err := retry(3, time.Second*30, func() error { | |||||
| _, err := modelarts.StopJob(taskInfo.JobID, param) | |||||
| return err | |||||
| }) | |||||
| logErrorAndUpdateJobStatus(err, taskInfo) | |||||
| } | } | ||||
| } | } | ||||
| @@ -510,8 +478,7 @@ func CloudBrainDel(ctx *context.Context) { | |||||
| ctx.ServerError("DeleteJob failed", err) | ctx.ServerError("DeleteJob failed", err) | ||||
| return | return | ||||
| } | } | ||||
| ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/cloudbrain") | |||||
| ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob") | |||||
| } | } | ||||
| func CloudBrainShowModels(ctx *context.Context) { | func CloudBrainShowModels(ctx *context.Context) { | ||||
| @@ -528,10 +495,10 @@ func CloudBrainShowModels(ctx *context.Context) { | |||||
| } | } | ||||
| //get dirs | //get dirs | ||||
| dirs, err := getModelDirs(task.JobName, parentDir) | |||||
| dirs, err := GetModelDirs(task.JobName, parentDir) | |||||
| if err != nil { | if err != nil { | ||||
| log.Error("getModelDirs failed:%v", err.Error(), ctx.Data["msgID"]) | |||||
| ctx.ServerError("getModelDirs failed:", err) | |||||
| log.Error("GetModelDirs failed:%v", err.Error(), ctx.Data["msgID"]) | |||||
| ctx.ServerError("GetModelDirs failed:", err) | |||||
| return | return | ||||
| } | } | ||||
| @@ -591,9 +558,9 @@ func getImages(ctx *context.Context, imageType string) { | |||||
| log.Info("Get images end") | log.Info("Get images end") | ||||
| } | } | ||||
| func getModelDirs(jobName string, parentDir string) (string, error) { | |||||
| func GetModelDirs(jobName string, parentDir string) (string, error) { | |||||
| var req string | var req string | ||||
| modelActualPath := setting.JobPath + jobName + "/model/" | |||||
| modelActualPath := getMinioPath(jobName, cloudbrain.ModelMountPath+"/") | |||||
| if parentDir == "" { | if parentDir == "" { | ||||
| req = "baseDir=" + modelActualPath | req = "baseDir=" + modelActualPath | ||||
| } else { | } else { | ||||
| @@ -603,6 +570,10 @@ func getModelDirs(jobName string, parentDir string) (string, error) { | |||||
| return getDirs(req) | return getDirs(req) | ||||
| } | } | ||||
| func getMinioPath(jobName, suffixPath string) string { | |||||
| return setting.Attachment.Minio.RealPath + setting.Attachment.Minio.Bucket + "/" + setting.CBCodePathPrefix + jobName + suffixPath | |||||
| } | |||||
| func CloudBrainDownloadModel(ctx *context.Context) { | func CloudBrainDownloadModel(ctx *context.Context) { | ||||
| parentDir := ctx.Query("parentDir") | parentDir := ctx.Query("parentDir") | ||||
| fileName := ctx.Query("fileName") | fileName := ctx.Query("fileName") | ||||
| @@ -684,19 +655,21 @@ func downloadCode(repo *models.Repository, codePath string) error { | |||||
| return nil | return nil | ||||
| } | } | ||||
| func downloadRateCode(repo *models.Repository, taskName, gitPath, codePath, benchmarkCategory, gpuType string) error { | |||||
| func downloadRateCode(repo *models.Repository, taskName, rateOwnerName, rateRepoName, codePath, benchmarkCategory, gpuType string) error { | |||||
| err := os.MkdirAll(codePath, os.ModePerm) | err := os.MkdirAll(codePath, os.ModePerm) | ||||
| if err != nil { | if err != nil { | ||||
| log.Error("mkdir codePath failed", err.Error()) | log.Error("mkdir codePath failed", err.Error()) | ||||
| return err | return err | ||||
| } | } | ||||
| command := "git clone " + gitPath + " " + codePath | |||||
| cmd := exec.Command("/bin/bash", "-c", command) | |||||
| output, err := cmd.Output() | |||||
| log.Info(string(output)) | |||||
| repoExt, err := models.GetRepositoryByOwnerAndName(rateOwnerName, rateRepoName) | |||||
| if err != nil { | if err != nil { | ||||
| log.Error("exec.Command(%s) failed:%v", command, err) | |||||
| log.Error("GetRepositoryByOwnerAndName(%s) failed", rateRepoName, err.Error()) | |||||
| return err | |||||
| } | |||||
| if err := git.Clone(repoExt.RepoPath(), codePath, git.CloneRepoOptions{}); err != nil { | |||||
| log.Error("Failed to clone repository: %s (%v)", repoExt.FullName(), err) | |||||
| return err | return err | ||||
| } | } | ||||
| @@ -730,3 +703,144 @@ func downloadRateCode(repo *models.Repository, taskName, gitPath, codePath, benc | |||||
| return nil | return nil | ||||
| } | } | ||||
| func uploadCodeToMinio(codePath, jobName, parentDir string) error { | |||||
| files, err := readDir(codePath) | |||||
| if err != nil { | |||||
| log.Error("readDir(%s) failed: %s", codePath, err.Error()) | |||||
| return err | |||||
| } | |||||
| for _, file := range files { | |||||
| if file.IsDir() { | |||||
| if err = uploadCodeToMinio(codePath+file.Name()+"/", jobName, parentDir+file.Name()+"/"); err != nil { | |||||
| log.Error("uploadCodeToMinio(%s) failed: %s", file.Name(), err.Error()) | |||||
| return err | |||||
| } | |||||
| } else { | |||||
| destObject := setting.CBCodePathPrefix + jobName + parentDir + file.Name() | |||||
| sourceFile := codePath + file.Name() | |||||
| err = storage.Attachments.UploadObject(destObject, sourceFile) | |||||
| if err != nil { | |||||
| log.Error("UploadObject(%s) failed: %s", file.Name(), err.Error()) | |||||
| return err | |||||
| } | |||||
| } | |||||
| } | |||||
| return nil | |||||
| } | |||||
| func mkModelPath(modelPath string) error { | |||||
| err := os.MkdirAll(modelPath, os.ModePerm) | |||||
| if err != nil { | |||||
| log.Error("MkdirAll(%s) failed:%v", modelPath, err) | |||||
| return err | |||||
| } | |||||
| fileName := modelPath + "README" | |||||
| f, err := os.OpenFile(fileName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.ModePerm) | |||||
| if err != nil { | |||||
| log.Error("OpenFile failed", err.Error()) | |||||
| return err | |||||
| } | |||||
| defer f.Close() | |||||
| _, err = f.WriteString("You can put the model file into this directory and download it by the web page.") | |||||
| if err != nil { | |||||
| log.Error("WriteString failed", err.Error()) | |||||
| return err | |||||
| } | |||||
| return nil | |||||
| } | |||||
| func SyncCloudbrainStatus() { | |||||
| cloudBrains, err := models.GetCloudBrainUnStoppedJob() | |||||
| if err != nil { | |||||
| log.Error("GetCloudBrainUnStoppedJob failed:", err.Error()) | |||||
| return | |||||
| } | |||||
| for _, task := range cloudBrains { | |||||
| if task.Type == models.TypeCloudBrainOne { | |||||
| result, err := cloudbrain.GetJob(task.JobID) | |||||
| if err != nil { | |||||
| log.Error("GetJob(%s) failed:%v", task.JobName, err) | |||||
| continue | |||||
| } | |||||
| if result != nil { | |||||
| jobRes, _ := models.ConvertToJobResultPayload(result.Payload) | |||||
| taskRoles := jobRes.TaskRoles | |||||
| taskRes, _ := models.ConvertToTaskPod(taskRoles[cloudbrain.SubTaskName].(map[string]interface{})) | |||||
| task.Status = taskRes.TaskStatuses[0].State | |||||
| if task.Status != string(models.JobWaiting) { | |||||
| task.Duration = time.Now().Unix() - taskRes.TaskStatuses[0].StartAt.Unix() | |||||
| err = models.UpdateJob(task) | |||||
| if err != nil { | |||||
| log.Error("UpdateJob(%s) failed:%v", task.JobName, err) | |||||
| } | |||||
| if task.Duration >= setting.MaxDuration { | |||||
| log.Info("begin to stop job(%s), because of the duration", task.JobName) | |||||
| err = cloudbrain.StopJob(task.JobID) | |||||
| if err != nil { | |||||
| log.Error("StopJob(%s) failed:%v", task.JobName, err) | |||||
| continue | |||||
| } | |||||
| task.Status = string(models.JobStopped) | |||||
| err = models.UpdateJob(task) | |||||
| if err != nil { | |||||
| log.Error("UpdateJob(%s) failed:%v", task.JobName, err) | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } else if task.Type == models.TypeCloudBrainTwo { | |||||
| if task.JobType == string(models.JobTypeDebug) { | |||||
| result, err := modelarts.GetJob(task.JobID) | |||||
| if err != nil { | |||||
| log.Error("GetJob(%s) failed:%v", task.JobName, err) | |||||
| continue | |||||
| } | |||||
| if result != nil { | |||||
| task.Status = result.Status | |||||
| err = models.UpdateJob(task) | |||||
| if err != nil { | |||||
| log.Error("UpdateJob(%s) failed:%v", task.JobName, err) | |||||
| continue | |||||
| } | |||||
| } | |||||
| } else if task.JobType == string(models.JobTypeTrain) { | |||||
| result, err := modelarts.GetTrainJob(task.JobID, strconv.FormatInt(task.VersionID, 10)) | |||||
| if err != nil { | |||||
| log.Error("GetTrainJob(%s) failed:%v", task.JobName, err) | |||||
| continue | |||||
| } | |||||
| if result != nil { | |||||
| task.Status = modelarts.TransTrainJobStatus(result.IntStatus) | |||||
| task.Duration = result.Duration | |||||
| task.TrainJobDuration = result.TrainJobDuration | |||||
| err = models.UpdateJob(task) | |||||
| if err != nil { | |||||
| log.Error("UpdateJob(%s) failed:%v", task.JobName, err) | |||||
| continue | |||||
| } | |||||
| } | |||||
| } else { | |||||
| log.Error("task.JobType(%s) is error:%s", task.JobName, task.JobType) | |||||
| } | |||||
| } else { | |||||
| log.Error("task.Type(%s) is error:%d", task.JobName, task.Type) | |||||
| } | |||||
| } | |||||
| return | |||||
| } | |||||
| @@ -12,7 +12,6 @@ import ( | |||||
| "code.gitea.io/gitea/modules/base" | "code.gitea.io/gitea/modules/base" | ||||
| "code.gitea.io/gitea/modules/context" | "code.gitea.io/gitea/modules/context" | ||||
| "code.gitea.io/gitea/modules/log" | "code.gitea.io/gitea/modules/log" | ||||
| "code.gitea.io/gitea/modules/obs" | |||||
| "code.gitea.io/gitea/modules/setting" | "code.gitea.io/gitea/modules/setting" | ||||
| "code.gitea.io/gitea/modules/storage" | "code.gitea.io/gitea/modules/storage" | ||||
| ) | ) | ||||
| @@ -70,40 +69,10 @@ func DeleteAllUnzipFile(attachment *models.Attachment, parentDir string) { | |||||
| } | } | ||||
| } | } | ||||
| if attachment.Type == models.TypeCloudBrainTwo { | if attachment.Type == models.TypeCloudBrainTwo { | ||||
| input := &obs.ListObjectsInput{} | |||||
| input.Bucket = setting.Bucket | |||||
| // 设置每页100个对象 | |||||
| input.MaxKeys = 100 | |||||
| input.Prefix = setting.BasePath + attachment.RelativePath() + attachment.UUID | |||||
| index := 1 | |||||
| log.Info("prefix=" + input.Prefix) | |||||
| for { | |||||
| output, err := storage.ObsCli.ListObjects(input) | |||||
| if err == nil { | |||||
| log.Info("Page:%d\n", index) | |||||
| index++ | |||||
| for _, val := range output.Contents { | |||||
| log.Info("delete obs file:" + val.Key) | |||||
| delObj := &obs.DeleteObjectInput{} | |||||
| delObj.Bucket = setting.Bucket | |||||
| delObj.Key = val.Key | |||||
| storage.ObsCli.DeleteObject(delObj) | |||||
| } | |||||
| if output.IsTruncated { | |||||
| input.Marker = output.NextMarker | |||||
| } else { | |||||
| break | |||||
| } | |||||
| } else { | |||||
| if obsError, ok := err.(obs.ObsError); ok { | |||||
| log.Info("Code:%s\n", obsError.Code) | |||||
| log.Info("Message:%s\n", obsError.Message) | |||||
| } | |||||
| break | |||||
| } | |||||
| err := storage.ObsRemoveObject(setting.Bucket, setting.BasePath+attachment.RelativePath()+attachment.UUID) | |||||
| if err != nil { | |||||
| log.Info("delete file error.") | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -257,7 +257,6 @@ func HTTP(ctx *context.Context) { | |||||
| models.EnvPusherID + fmt.Sprintf("=%d", authUser.ID), | models.EnvPusherID + fmt.Sprintf("=%d", authUser.ID), | ||||
| models.EnvIsDeployKey + "=false", | models.EnvIsDeployKey + "=false", | ||||
| } | } | ||||
| if !authUser.KeepEmailPrivate { | if !authUser.KeepEmailPrivate { | ||||
| environ = append(environ, models.EnvPusherEmail+"="+authUser.Email) | environ = append(environ, models.EnvPusherEmail+"="+authUser.Email) | ||||
| } | } | ||||
| @@ -559,6 +558,7 @@ func serviceRPC(h serviceHandler, service string) { | |||||
| if service == "receive-pack" { | if service == "receive-pack" { | ||||
| cmd.Env = append(os.Environ(), h.environ...) | cmd.Env = append(os.Environ(), h.environ...) | ||||
| } | } | ||||
| cmd.Stdout = h.w | cmd.Stdout = h.w | ||||
| cmd.Stdin = reqBody | cmd.Stdin = reqBody | ||||
| cmd.Stderr = &stderr | cmd.Stderr = &stderr | ||||
| @@ -1390,7 +1390,7 @@ func isLegalReviewRequest(reviewer, doer *models.User, isAdd bool, issue *models | |||||
| var pemResult bool | var pemResult bool | ||||
| if isAdd { | if isAdd { | ||||
| pemResult = permReviewer.CanAccessAny(models.AccessModeRead, models.UnitTypePullRequests) | |||||
| pemResult = permReviewer.CanAccessAny(models.AccessModeWrite, models.UnitTypePullRequests) | |||||
| if !pemResult { | if !pemResult { | ||||
| return fmt.Errorf("Reviewer can't read [user_id: %d, repo_name: %s]", reviewer.ID, issue.Repo.Name) | return fmt.Errorf("Reviewer can't read [user_id: %d, repo_name: %s]", reviewer.ID, issue.Repo.Name) | ||||
| } | } | ||||
| @@ -4,7 +4,6 @@ import ( | |||||
| "encoding/json" | "encoding/json" | ||||
| "errors" | "errors" | ||||
| "io" | "io" | ||||
| "io/ioutil" | |||||
| "net/http" | "net/http" | ||||
| "os" | "os" | ||||
| "path" | "path" | ||||
| @@ -12,6 +11,8 @@ import ( | |||||
| "strings" | "strings" | ||||
| "time" | "time" | ||||
| "code.gitea.io/gitea/modules/cloudbrain" | |||||
| "code.gitea.io/gitea/models" | "code.gitea.io/gitea/models" | ||||
| "code.gitea.io/gitea/modules/auth" | "code.gitea.io/gitea/modules/auth" | ||||
| "code.gitea.io/gitea/modules/base" | "code.gitea.io/gitea/modules/base" | ||||
| @@ -27,6 +28,8 @@ import ( | |||||
| ) | ) | ||||
| const ( | const ( | ||||
| tplDebugJobIndex base.TplName = "repo/debugjob/index" | |||||
| tplModelArtsNotebookIndex base.TplName = "repo/modelarts/notebook/index" | tplModelArtsNotebookIndex base.TplName = "repo/modelarts/notebook/index" | ||||
| tplModelArtsNotebookNew base.TplName = "repo/modelarts/notebook/new" | tplModelArtsNotebookNew base.TplName = "repo/modelarts/notebook/new" | ||||
| tplModelArtsNotebookShow base.TplName = "repo/modelarts/notebook/show" | tplModelArtsNotebookShow base.TplName = "repo/modelarts/notebook/show" | ||||
| @@ -37,21 +40,23 @@ const ( | |||||
| tplModelArtsTrainJobVersionNew base.TplName = "repo/modelarts/trainjob/version_new" | tplModelArtsTrainJobVersionNew base.TplName = "repo/modelarts/trainjob/version_new" | ||||
| ) | ) | ||||
| // MustEnableDataset check if repository enable internal cb | |||||
| func MustEnableModelArts(ctx *context.Context) { | |||||
| if !ctx.Repo.CanRead(models.UnitTypeCloudBrain) { | |||||
| ctx.NotFound("MustEnableCloudbrain", nil) | |||||
| return | |||||
| } | |||||
| } | |||||
| func NotebookIndex(ctx *context.Context) { | |||||
| MustEnableModelArts(ctx) | |||||
| func DebugJobIndex(ctx *context.Context) { | |||||
| debugListType := ctx.Query("debugListType") | |||||
| MustEnableCloudbrain(ctx) | |||||
| repo := ctx.Repo.Repository | repo := ctx.Repo.Repository | ||||
| page := ctx.QueryInt("page") | page := ctx.QueryInt("page") | ||||
| if page <= 0 { | if page <= 0 { | ||||
| page = 1 | page = 1 | ||||
| } | } | ||||
| debugType := modelarts.DebugType | |||||
| jobType := string(models.JobTypeDebug) | |||||
| if debugListType == modelarts.GPUResource { | |||||
| debugType = models.TypeCloudBrainOne | |||||
| jobType = "" | |||||
| } | |||||
| if debugListType == modelarts.NPUResource { | |||||
| debugType = models.TypeCloudBrainTwo | |||||
| } | |||||
| ciTasks, count, err := models.Cloudbrains(&models.CloudbrainsOptions{ | ciTasks, count, err := models.Cloudbrains(&models.CloudbrainsOptions{ | ||||
| ListOptions: models.ListOptions{ | ListOptions: models.ListOptions{ | ||||
| @@ -59,29 +64,44 @@ func NotebookIndex(ctx *context.Context) { | |||||
| PageSize: setting.UI.IssuePagingNum, | PageSize: setting.UI.IssuePagingNum, | ||||
| }, | }, | ||||
| RepoID: repo.ID, | RepoID: repo.ID, | ||||
| Type: models.TypeCloudBrainTwo, | |||||
| JobType: string(models.JobTypeDebug), | |||||
| Type: debugType, | |||||
| JobType: jobType, | |||||
| }) | }) | ||||
| if err != nil { | if err != nil { | ||||
| ctx.ServerError("Cloudbrain", err) | |||||
| ctx.ServerError("Get debugjob faild:", err) | |||||
| return | return | ||||
| } | } | ||||
| for i, task := range ciTasks { | for i, task := range ciTasks { | ||||
| if task.Status == string(models.JobRunning) { | |||||
| ciTasks[i].CanDebug = true | |||||
| } else { | |||||
| ciTasks[i].CanDebug = false | |||||
| if task.Cloudbrain.Type == models.TypeCloudBrainOne { | |||||
| ciTasks[i].CanDebug = cloudbrain.CanCreateOrDebugJob(ctx) | |||||
| ciTasks[i].CanDel = cloudbrain.CanDeleteJob(ctx, &task.Cloudbrain) | |||||
| ciTasks[i].Cloudbrain.ComputeResource = modelarts.GPUResource | |||||
| } | |||||
| if task.Cloudbrain.Type == models.TypeCloudBrainTwo { | |||||
| ciTasks[i].CanDebug = cloudbrain.CanCreateOrDebugJob(ctx) | |||||
| ciTasks[i].CanDel = cloudbrain.CanDeleteJob(ctx, &task.Cloudbrain) | |||||
| ciTasks[i].Cloudbrain.ComputeResource = modelarts.NPUResource | |||||
| } | } | ||||
| } | } | ||||
| pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, 5) | pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, 5) | ||||
| pager.SetDefaultParams(ctx) | pager.SetDefaultParams(ctx) | ||||
| ctx.Data["Page"] = pager | ctx.Data["Page"] = pager | ||||
| ctx.Data["PageIsCloudBrain"] = true | ctx.Data["PageIsCloudBrain"] = true | ||||
| ctx.Data["Tasks"] = ciTasks | ctx.Data["Tasks"] = ciTasks | ||||
| ctx.HTML(200, tplModelArtsNotebookIndex) | |||||
| ctx.Data["CanCreate"] = cloudbrain.CanCreateOrDebugJob(ctx) | |||||
| ctx.Data["RepoIsEmpty"] = repo.IsEmpty | |||||
| ctx.HTML(200, tplDebugJobIndex) | |||||
| } | |||||
| // MustEnableDataset check if repository enable internal cb | |||||
| func MustEnableModelArts(ctx *context.Context) { | |||||
| if !ctx.Repo.CanRead(models.UnitTypeCloudBrain) { | |||||
| ctx.NotFound("MustEnableCloudbrain", nil) | |||||
| return | |||||
| } | |||||
| } | } | ||||
| func NotebookNew(ctx *context.Context) { | func NotebookNew(ctx *context.Context) { | ||||
| @@ -136,8 +156,7 @@ func NotebookCreate(ctx *context.Context, form auth.CreateModelArtsNotebookForm) | |||||
| ctx.RenderWithErr(err.Error(), tplModelArtsNotebookNew, &form) | ctx.RenderWithErr(err.Error(), tplModelArtsNotebookNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/notebook") | |||||
| ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob") | |||||
| } | } | ||||
| func NotebookShow(ctx *context.Context) { | func NotebookShow(ctx *context.Context) { | ||||
| @@ -244,8 +263,7 @@ func NotebookStop(ctx *context.Context) { | |||||
| ctx.ServerError("UpdateJob failed", err) | ctx.ServerError("UpdateJob failed", err) | ||||
| return | return | ||||
| } | } | ||||
| ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/notebook") | |||||
| ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob") | |||||
| } | } | ||||
| func NotebookDel(ctx *context.Context) { | func NotebookDel(ctx *context.Context) { | ||||
| @@ -275,7 +293,7 @@ func NotebookDel(ctx *context.Context) { | |||||
| return | return | ||||
| } | } | ||||
| ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/notebook") | |||||
| ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob") | |||||
| } | } | ||||
| func TrainJobIndex(ctx *context.Context) { | func TrainJobIndex(ctx *context.Context) { | ||||
| @@ -302,12 +320,19 @@ func TrainJobIndex(ctx *context.Context) { | |||||
| return | return | ||||
| } | } | ||||
| for i, task := range tasks { | |||||
| tasks[i].CanDel = cloudbrain.CanDeleteJob(ctx, &task.Cloudbrain) | |||||
| tasks[i].CanModify = cloudbrain.CanModifyJob(ctx, &task.Cloudbrain) | |||||
| } | |||||
| pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, 5) | pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, 5) | ||||
| pager.SetDefaultParams(ctx) | pager.SetDefaultParams(ctx) | ||||
| ctx.Data["Page"] = pager | ctx.Data["Page"] = pager | ||||
| ctx.Data["PageIsCloudBrain"] = true | ctx.Data["PageIsCloudBrain"] = true | ||||
| ctx.Data["Tasks"] = tasks | ctx.Data["Tasks"] = tasks | ||||
| ctx.Data["CanCreate"] = cloudbrain.CanCreateOrDebugJob(ctx) | |||||
| ctx.Data["RepoIsEmpty"] = repo.IsEmpty | |||||
| ctx.HTML(200, tplModelArtsTrainJobIndex) | ctx.HTML(200, tplModelArtsTrainJobIndex) | ||||
| } | } | ||||
| @@ -376,9 +401,8 @@ func trainJobNewDataPrepare(ctx *context.Context) error { | |||||
| outputObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.OutputPath | outputObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.OutputPath | ||||
| ctx.Data["train_url"] = outputObsPath | ctx.Data["train_url"] = outputObsPath | ||||
| ctx.Data["params"] = "" | ctx.Data["params"] = "" | ||||
| ctx.Data["BranchName"] = ctx.Repo.BranchName | |||||
| ctx.Data["branchName"] = ctx.Repo.BranchName | |||||
| configList, err := getConfigList(modelarts.PerPage, 1, modelarts.SortByCreateTime, "desc", "", modelarts.ConfigTypeCustom) | configList, err := getConfigList(modelarts.PerPage, 1, modelarts.SortByCreateTime, "desc", "", modelarts.ConfigTypeCustom) | ||||
| if err != nil { | if err != nil { | ||||
| @@ -390,7 +414,7 @@ func trainJobNewDataPrepare(ctx *context.Context) error { | |||||
| return nil | return nil | ||||
| } | } | ||||
| func ErrorNewDataPrepare(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) error { | |||||
| func trainJobErrorNewDataPrepare(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) error { | |||||
| ctx.Data["PageIsCloudBrain"] = true | ctx.Data["PageIsCloudBrain"] = true | ||||
| //can, err := canUserCreateTrainJob(ctx.User.ID) | //can, err := canUserCreateTrainJob(ctx.User.ID) | ||||
| @@ -570,7 +594,7 @@ func trainJobNewVersionDataPrepare(ctx *context.Context) error { | |||||
| return nil | return nil | ||||
| } | } | ||||
| func VersionErrorDataPrepare(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) error { | |||||
| func versionErrorDataPrepare(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) error { | |||||
| ctx.Data["PageIsCloudBrain"] = true | ctx.Data["PageIsCloudBrain"] = true | ||||
| var jobID = ctx.Params(":jobid") | var jobID = ctx.Params(":jobid") | ||||
| // var versionName = ctx.Params(":version-name") | // var versionName = ctx.Params(":version-name") | ||||
| @@ -687,13 +711,13 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||||
| count, err := models.GetCloudbrainTrainJobCountByUserID(ctx.User.ID) | count, err := models.GetCloudbrainTrainJobCountByUserID(ctx.User.ID) | ||||
| if err != nil { | if err != nil { | ||||
| log.Error("GetCloudbrainTrainJobCountByUserID failed:%v", err, ctx.Data["MsgID"]) | log.Error("GetCloudbrainTrainJobCountByUserID failed:%v", err, ctx.Data["MsgID"]) | ||||
| ErrorNewDataPrepare(ctx, form) | |||||
| trainJobErrorNewDataPrepare(ctx, form) | |||||
| ctx.RenderWithErr("system error", tplModelArtsTrainJobNew, &form) | ctx.RenderWithErr("system error", tplModelArtsTrainJobNew, &form) | ||||
| return | return | ||||
| } else { | } else { | ||||
| if count >= 1 { | if count >= 1 { | ||||
| log.Error("the user already has running or waiting task", ctx.Data["MsgID"]) | log.Error("the user already has running or waiting task", ctx.Data["MsgID"]) | ||||
| ErrorNewDataPrepare(ctx, form) | |||||
| trainJobErrorNewDataPrepare(ctx, form) | |||||
| ctx.RenderWithErr("you have already a running or waiting task, can not create more", tplModelArtsTrainJobNew, &form) | ctx.RenderWithErr("you have already a running or waiting task, can not create more", tplModelArtsTrainJobNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| @@ -701,22 +725,23 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||||
| if err := paramCheckCreateTrainJob(form); err != nil { | if err := paramCheckCreateTrainJob(form); err != nil { | ||||
| log.Error("paramCheckCreateTrainJob failed:(%v)", err) | log.Error("paramCheckCreateTrainJob failed:(%v)", err) | ||||
| ErrorNewDataPrepare(ctx, form) | |||||
| trainJobErrorNewDataPrepare(ctx, form) | |||||
| ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobNew, &form) | ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| attach, err := models.GetAttachmentByUUID(uuid) | |||||
| if err != nil { | |||||
| log.Error("GetAttachmentByUUID(%s) failed:%v", uuid, err.Error()) | |||||
| return | |||||
| } | |||||
| // attach, err := models.GetAttachmentByUUID(uuid) | |||||
| // if err != nil { | |||||
| // log.Error("GetAttachmentByUUID(%s) failed:%v", uuid, err.Error()) | |||||
| // return | |||||
| // } | |||||
| //todo: del the codeLocalPath | //todo: del the codeLocalPath | ||||
| _, err = ioutil.ReadDir(codeLocalPath) | |||||
| if err == nil { | |||||
| os.RemoveAll(codeLocalPath) | |||||
| } | |||||
| // _, err := ioutil.ReadDir(codeLocalPath) | |||||
| // if err == nil { | |||||
| // os.RemoveAll(codeLocalPath) | |||||
| // } | |||||
| os.RemoveAll(codeLocalPath) | |||||
| gitRepo, _ := git.OpenRepository(repo.RepoPath()) | gitRepo, _ := git.OpenRepository(repo.RepoPath()) | ||||
| commitID, _ := gitRepo.GetBranchCommitID(branch_name) | commitID, _ := gitRepo.GetBranchCommitID(branch_name) | ||||
| @@ -725,7 +750,7 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||||
| Branch: branch_name, | Branch: branch_name, | ||||
| }); err != nil { | }); err != nil { | ||||
| log.Error("创建任务失败,服务器超时!: %s (%v)", repo.FullName(), err) | log.Error("创建任务失败,服务器超时!: %s (%v)", repo.FullName(), err) | ||||
| trainJobNewDataPrepare(ctx) | |||||
| trainJobErrorNewDataPrepare(ctx, form) | |||||
| ctx.RenderWithErr("创建任务失败,服务器超时!", tplModelArtsTrainJobNew, &form) | ctx.RenderWithErr("创建任务失败,服务器超时!", tplModelArtsTrainJobNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| @@ -733,14 +758,14 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||||
| //todo: upload code (send to file_server todo this work?) | //todo: upload code (send to file_server todo this work?) | ||||
| if err := obsMkdir(setting.CodePathPrefix + jobName + modelarts.OutputPath + VersionOutputPath + "/"); err != nil { | if err := obsMkdir(setting.CodePathPrefix + jobName + modelarts.OutputPath + VersionOutputPath + "/"); err != nil { | ||||
| log.Error("Failed to obsMkdir_output: %s (%v)", repo.FullName(), err) | log.Error("Failed to obsMkdir_output: %s (%v)", repo.FullName(), err) | ||||
| trainJobNewDataPrepare(ctx) | |||||
| trainJobErrorNewDataPrepare(ctx, form) | |||||
| ctx.RenderWithErr("Failed to obsMkdir_output", tplModelArtsTrainJobNew, &form) | ctx.RenderWithErr("Failed to obsMkdir_output", tplModelArtsTrainJobNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| if err := obsMkdir(setting.CodePathPrefix + jobName + modelarts.LogPath + VersionOutputPath + "/"); err != nil { | if err := obsMkdir(setting.CodePathPrefix + jobName + modelarts.LogPath + VersionOutputPath + "/"); err != nil { | ||||
| log.Error("Failed to obsMkdir_log: %s (%v)", repo.FullName(), err) | log.Error("Failed to obsMkdir_log: %s (%v)", repo.FullName(), err) | ||||
| trainJobNewDataPrepare(ctx) | |||||
| trainJobErrorNewDataPrepare(ctx, form) | |||||
| ctx.RenderWithErr("Failed to obsMkdir_log", tplModelArtsTrainJobNew, &form) | ctx.RenderWithErr("Failed to obsMkdir_log", tplModelArtsTrainJobNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| @@ -749,7 +774,7 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||||
| if err := uploadCodeToObs(codeLocalPath, jobName, ""); err != nil { | if err := uploadCodeToObs(codeLocalPath, jobName, ""); err != nil { | ||||
| // if err := uploadCodeToObs(codeLocalPath, jobName, parentDir); err != nil { | // if err := uploadCodeToObs(codeLocalPath, jobName, parentDir); err != nil { | ||||
| log.Error("Failed to uploadCodeToObs: %s (%v)", repo.FullName(), err) | log.Error("Failed to uploadCodeToObs: %s (%v)", repo.FullName(), err) | ||||
| trainJobNewDataPrepare(ctx) | |||||
| trainJobErrorNewDataPrepare(ctx, form) | |||||
| ctx.RenderWithErr("Failed to uploadCodeToObs", tplModelArtsTrainJobNew, &form) | ctx.RenderWithErr("Failed to uploadCodeToObs", tplModelArtsTrainJobNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| @@ -769,7 +794,7 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||||
| err := json.Unmarshal([]byte(params), ¶meters) | err := json.Unmarshal([]byte(params), ¶meters) | ||||
| if err != nil { | if err != nil { | ||||
| log.Error("Failed to Unmarshal params: %s (%v)", params, err) | log.Error("Failed to Unmarshal params: %s (%v)", params, err) | ||||
| trainJobNewDataPrepare(ctx) | |||||
| trainJobErrorNewDataPrepare(ctx, form) | |||||
| ctx.RenderWithErr("运行参数错误", tplModelArtsTrainJobNew, &form) | ctx.RenderWithErr("运行参数错误", tplModelArtsTrainJobNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| @@ -812,7 +837,7 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||||
| if err != nil { | if err != nil { | ||||
| log.Error("Failed to CreateTrainJobConfig: %v", err) | log.Error("Failed to CreateTrainJobConfig: %v", err) | ||||
| trainJobNewDataPrepare(ctx) | |||||
| trainJobErrorNewDataPrepare(ctx, form) | |||||
| ctx.RenderWithErr("保存作业参数失败:"+err.Error(), tplModelArtsTrainJobNew, &form) | ctx.RenderWithErr("保存作业参数失败:"+err.Error(), tplModelArtsTrainJobNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| @@ -853,12 +878,7 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||||
| err = modelarts.GenerateTrainJob(ctx, req) | err = modelarts.GenerateTrainJob(ctx, req) | ||||
| if err != nil { | if err != nil { | ||||
| log.Error("GenerateTrainJob failed:%v", err.Error()) | 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"] = Parameters.Parameter | |||||
| ctx.Data["branch_name"] = branch_name | |||||
| trainJobErrorNewDataPrepare(ctx, form) | |||||
| ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobNew, &form) | ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| @@ -872,13 +892,13 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ | |||||
| count, err := models.GetCloudbrainTrainJobCountByUserID(ctx.User.ID) | count, err := models.GetCloudbrainTrainJobCountByUserID(ctx.User.ID) | ||||
| if err != nil { | if err != nil { | ||||
| log.Error("GetCloudbrainTrainJobCountByUserID failed:%v", err, ctx.Data["MsgID"]) | log.Error("GetCloudbrainTrainJobCountByUserID failed:%v", err, ctx.Data["MsgID"]) | ||||
| VersionErrorDataPrepare(ctx, form) | |||||
| versionErrorDataPrepare(ctx, form) | |||||
| ctx.RenderWithErr("system error", tplModelArtsTrainJobVersionNew, &form) | ctx.RenderWithErr("system error", tplModelArtsTrainJobVersionNew, &form) | ||||
| return | return | ||||
| } else { | } else { | ||||
| if count >= 1 { | if count >= 1 { | ||||
| log.Error("the user already has running or waiting task", ctx.Data["MsgID"]) | log.Error("the user already has running or waiting task", ctx.Data["MsgID"]) | ||||
| VersionErrorDataPrepare(ctx, form) | |||||
| versionErrorDataPrepare(ctx, form) | |||||
| ctx.RenderWithErr("you have already a running or waiting task, can not create more", tplModelArtsTrainJobVersionNew, &form) | ctx.RenderWithErr("you have already a running or waiting task, can not create more", tplModelArtsTrainJobVersionNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| @@ -922,7 +942,7 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ | |||||
| if err := paramCheckCreateTrainJob(form); err != nil { | if err := paramCheckCreateTrainJob(form); err != nil { | ||||
| log.Error("paramCheckCreateTrainJob failed:(%v)", err) | log.Error("paramCheckCreateTrainJob failed:(%v)", err) | ||||
| VersionErrorDataPrepare(ctx, form) | |||||
| versionErrorDataPrepare(ctx, form) | |||||
| ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobVersionNew, &form) | ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobVersionNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| @@ -946,7 +966,7 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ | |||||
| Branch: branch_name, | Branch: branch_name, | ||||
| }); err != nil { | }); err != nil { | ||||
| log.Error("创建任务失败,任务名称已存在!: %s (%v)", repo.FullName(), err) | log.Error("创建任务失败,任务名称已存在!: %s (%v)", repo.FullName(), err) | ||||
| VersionErrorDataPrepare(ctx, form) | |||||
| versionErrorDataPrepare(ctx, form) | |||||
| ctx.RenderWithErr("创建任务失败,任务名称已存在!", tplModelArtsTrainJobVersionNew, &form) | ctx.RenderWithErr("创建任务失败,任务名称已存在!", tplModelArtsTrainJobVersionNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| @@ -954,14 +974,14 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ | |||||
| //todo: upload code (send to file_server todo this work?) | //todo: upload code (send to file_server todo this work?) | ||||
| if err := obsMkdir(setting.CodePathPrefix + jobName + modelarts.OutputPath + VersionOutputPath + "/"); err != nil { | if err := obsMkdir(setting.CodePathPrefix + jobName + modelarts.OutputPath + VersionOutputPath + "/"); err != nil { | ||||
| log.Error("Failed to obsMkdir_output: %s (%v)", repo.FullName(), err) | log.Error("Failed to obsMkdir_output: %s (%v)", repo.FullName(), err) | ||||
| VersionErrorDataPrepare(ctx, form) | |||||
| versionErrorDataPrepare(ctx, form) | |||||
| ctx.RenderWithErr("Failed to obsMkdir_output", tplModelArtsTrainJobVersionNew, &form) | ctx.RenderWithErr("Failed to obsMkdir_output", tplModelArtsTrainJobVersionNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| if err := obsMkdir(setting.CodePathPrefix + jobName + modelarts.LogPath + VersionOutputPath + "/"); err != nil { | if err := obsMkdir(setting.CodePathPrefix + jobName + modelarts.LogPath + VersionOutputPath + "/"); err != nil { | ||||
| log.Error("Failed to obsMkdir_log: %s (%v)", repo.FullName(), err) | log.Error("Failed to obsMkdir_log: %s (%v)", repo.FullName(), err) | ||||
| VersionErrorDataPrepare(ctx, form) | |||||
| versionErrorDataPrepare(ctx, form) | |||||
| ctx.RenderWithErr("Failed to obsMkdir_log", tplModelArtsTrainJobVersionNew, &form) | ctx.RenderWithErr("Failed to obsMkdir_log", tplModelArtsTrainJobVersionNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| @@ -971,7 +991,7 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ | |||||
| // if err := uploadCodeToObs(codeLocalPath, jobName, ""); err != nil { | // if err := uploadCodeToObs(codeLocalPath, jobName, ""); err != nil { | ||||
| if err := uploadCodeToObs(codeLocalPath, jobName, parentDir); err != nil { | if err := uploadCodeToObs(codeLocalPath, jobName, parentDir); err != nil { | ||||
| log.Error("Failed to uploadCodeToObs: %s (%v)", repo.FullName(), err) | log.Error("Failed to uploadCodeToObs: %s (%v)", repo.FullName(), err) | ||||
| VersionErrorDataPrepare(ctx, form) | |||||
| versionErrorDataPrepare(ctx, form) | |||||
| ctx.RenderWithErr("Failed to uploadCodeToObs", tplModelArtsTrainJobVersionNew, &form) | ctx.RenderWithErr("Failed to uploadCodeToObs", tplModelArtsTrainJobVersionNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| @@ -991,7 +1011,7 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ | |||||
| err := json.Unmarshal([]byte(params), ¶meters) | err := json.Unmarshal([]byte(params), ¶meters) | ||||
| if err != nil { | if err != nil { | ||||
| log.Error("Failed to Unmarshal params: %s (%v)", params, err) | log.Error("Failed to Unmarshal params: %s (%v)", params, err) | ||||
| VersionErrorDataPrepare(ctx, form) | |||||
| versionErrorDataPrepare(ctx, form) | |||||
| ctx.RenderWithErr("运行参数错误", tplModelArtsTrainJobVersionNew, &form) | ctx.RenderWithErr("运行参数错误", tplModelArtsTrainJobVersionNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| @@ -1010,7 +1030,7 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ | |||||
| if isSaveParam == "on" { | if isSaveParam == "on" { | ||||
| if form.ParameterTemplateName == "" { | if form.ParameterTemplateName == "" { | ||||
| log.Error("ParameterTemplateName is empty") | log.Error("ParameterTemplateName is empty") | ||||
| VersionErrorDataPrepare(ctx, form) | |||||
| versionErrorDataPrepare(ctx, form) | |||||
| ctx.RenderWithErr("保存作业参数时,作业参数名称不能为空", tplModelArtsTrainJobVersionNew, &form) | ctx.RenderWithErr("保存作业参数时,作业参数名称不能为空", tplModelArtsTrainJobVersionNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| @@ -1034,7 +1054,7 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ | |||||
| if err != nil { | if err != nil { | ||||
| log.Error("Failed to CreateTrainJobConfig: %v", err) | log.Error("Failed to CreateTrainJobConfig: %v", err) | ||||
| VersionErrorDataPrepare(ctx, form) | |||||
| versionErrorDataPrepare(ctx, form) | |||||
| ctx.RenderWithErr("保存作业参数失败:"+err.Error(), tplModelArtsTrainJobVersionNew, &form) | ctx.RenderWithErr("保存作业参数失败:"+err.Error(), tplModelArtsTrainJobVersionNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| @@ -1081,7 +1101,7 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ | |||||
| err = modelarts.GenerateTrainJobVersion(ctx, req, jobID) | err = modelarts.GenerateTrainJobVersion(ctx, req, jobID) | ||||
| if err != nil { | if err != nil { | ||||
| log.Error("GenerateTrainJob failed:%v", err.Error()) | log.Error("GenerateTrainJob failed:%v", err.Error()) | ||||
| VersionErrorDataPrepare(ctx, form) | |||||
| versionErrorDataPrepare(ctx, form) | |||||
| ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobVersionNew, &form) | ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobVersionNew, &form) | ||||
| return | return | ||||
| } | } | ||||
| @@ -1210,7 +1230,7 @@ func TrainJobShow(ctx *context.Context) { | |||||
| ctx.Data["canNewJob"] = canNewJob | ctx.Data["canNewJob"] = canNewJob | ||||
| //将运行参数转化为epoch_size = 3, device_target = Ascend的格式 | //将运行参数转化为epoch_size = 3, device_target = Ascend的格式 | ||||
| for i, _ := range VersionListTasks { | |||||
| for i, task := range VersionListTasks { | |||||
| var parameters models.Parameters | var parameters models.Parameters | ||||
| @@ -1231,6 +1251,9 @@ func TrainJobShow(ctx *context.Context) { | |||||
| } else { | } else { | ||||
| VersionListTasks[i].Parameters = "" | VersionListTasks[i].Parameters = "" | ||||
| } | } | ||||
| VersionListTasks[i].CanDel = cloudbrain.CanDeleteJob(ctx, &task.Cloudbrain) | |||||
| VersionListTasks[i].CanModify = cloudbrain.CanModifyJob(ctx, &task.Cloudbrain) | |||||
| } | } | ||||
| pager := context.NewPagination(VersionListCount, setting.UI.IssuePagingNum, page, 5) | pager := context.NewPagination(VersionListCount, setting.UI.IssuePagingNum, page, 5) | ||||
| @@ -532,6 +532,7 @@ func Download(ctx *context.Context) { | |||||
| } | } | ||||
| ctx.Repo.Repository.IncreaseCloneCnt() | ctx.Repo.Repository.IncreaseCloneCnt() | ||||
| ctx.Repo.Repository.IncreaseGitCloneCnt() | |||||
| ctx.ServeFile(archivePath, ctx.Repo.Repository.Name+"-"+refName+ext) | ctx.ServeFile(archivePath, ctx.Repo.Repository.Name+"-"+refName+ext) | ||||
| } | } | ||||
| @@ -239,6 +239,18 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) { | |||||
| deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeCloudBrain) | deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeCloudBrain) | ||||
| } | } | ||||
| if form.EnableModelManager && !models.UnitTypeModelManage.UnitGlobalDisabled() { | |||||
| units = append(units, models.RepoUnit{ | |||||
| RepoID: repo.ID, | |||||
| Type: models.UnitTypeModelManage, | |||||
| Config: &models.ModelManageConfig{ | |||||
| EnableModelManage: form.EnableModelManager, | |||||
| }, | |||||
| }) | |||||
| } else if !models.UnitTypeModelManage.UnitGlobalDisabled() { | |||||
| deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeModelManage) | |||||
| } | |||||
| if form.EnableWiki && form.EnableExternalWiki && !models.UnitTypeExternalWiki.UnitGlobalDisabled() { | if form.EnableWiki && form.EnableExternalWiki && !models.UnitTypeExternalWiki.UnitGlobalDisabled() { | ||||
| if !validation.IsValidExternalURL(form.ExternalWikiURL) { | if !validation.IsValidExternalURL(form.ExternalWikiURL) { | ||||
| ctx.Flash.Error(ctx.Tr("repo.settings.external_wiki_url_error")) | ctx.Flash.Error(ctx.Tr("repo.settings.external_wiki_url_error")) | ||||
| @@ -148,11 +148,6 @@ func QueryUserStaticDataPage(ctx *context.Context) { | |||||
| func TimingCountDataByDateAndReCount(date string, isReCount bool) { | func TimingCountDataByDateAndReCount(date string, isReCount bool) { | ||||
| if date == "refreshAll" { | |||||
| models.RefreshUserStaticAllTabel() | |||||
| return | |||||
| } | |||||
| t, _ := time.Parse("2006-01-02", date) | t, _ := time.Parse("2006-01-02", date) | ||||
| startTime := time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location()) | startTime := time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location()) | ||||
| @@ -205,10 +200,9 @@ func TimingCountDataByDateAndReCount(date string, isReCount bool) { | |||||
| log.Error("count user info error." + err.Error()) | log.Error("count user info error." + err.Error()) | ||||
| mailer.SendWarnNotifyMail(setting.Warn_Notify_Mails, warnEmailMessage) | mailer.SendWarnNotifyMail(setting.Warn_Notify_Mails, warnEmailMessage) | ||||
| } | } | ||||
| if isReCount { | |||||
| models.RefreshUserStaticAllTabel() | |||||
| } | |||||
| log.Info("start to count all user info data") | |||||
| //models.RefreshUserStaticAllTabel(wikiMap) | |||||
| log.Info("end to count all user info data") | |||||
| } | } | ||||
| func TimingCountDataByDate(date string) { | func TimingCountDataByDate(date string) { | ||||
| @@ -12,6 +12,8 @@ import ( | |||||
| "text/template" | "text/template" | ||||
| "time" | "time" | ||||
| "code.gitea.io/gitea/modules/cloudbrain" | |||||
| "code.gitea.io/gitea/routers/operation" | "code.gitea.io/gitea/routers/operation" | ||||
| "code.gitea.io/gitea/routers/private" | "code.gitea.io/gitea/routers/private" | ||||
| @@ -313,6 +315,8 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
| }) | }) | ||||
| m.Get("/", routers.Home) | m.Get("/", routers.Home) | ||||
| m.Get("/dashboard", routers.Dashboard) | m.Get("/dashboard", routers.Dashboard) | ||||
| m.Get("/recommend/org", routers.RecommendOrgFromPromote) | |||||
| m.Get("/recommend/repo", routers.RecommendRepoFromPromote) | |||||
| m.Group("/explore", func() { | m.Group("/explore", func() { | ||||
| m.Get("", func(ctx *context.Context) { | m.Get("", func(ctx *context.Context) { | ||||
| ctx.Redirect(setting.AppSubURL + "/explore/repos") | ctx.Redirect(setting.AppSubURL + "/explore/repos") | ||||
| @@ -612,6 +616,8 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
| reqRepoDatasetWriter := context.RequireRepoWriter(models.UnitTypeDatasets) | reqRepoDatasetWriter := context.RequireRepoWriter(models.UnitTypeDatasets) | ||||
| reqRepoCloudBrainReader := context.RequireRepoReader(models.UnitTypeCloudBrain) | reqRepoCloudBrainReader := context.RequireRepoReader(models.UnitTypeCloudBrain) | ||||
| reqRepoCloudBrainWriter := context.RequireRepoWriter(models.UnitTypeCloudBrain) | reqRepoCloudBrainWriter := context.RequireRepoWriter(models.UnitTypeCloudBrain) | ||||
| reqRepoModelManageReader := context.RequireRepoReader(models.UnitTypeModelManage) | |||||
| reqRepoModelManageWriter := context.RequireRepoWriter(models.UnitTypeModelManage) | |||||
| //reqRepoBlockChainReader := context.RequireRepoReader(models.UnitTypeBlockChain) | //reqRepoBlockChainReader := context.RequireRepoReader(models.UnitTypeBlockChain) | ||||
| //reqRepoBlockChainWriter := context.RequireRepoWriter(models.UnitTypeBlockChain) | //reqRepoBlockChainWriter := context.RequireRepoWriter(models.UnitTypeBlockChain) | ||||
| @@ -792,7 +798,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
| }, reqSignIn, context.RepoAssignment(), context.UnitTypes(), reqRepoAdmin, context.RepoRef()) | }, reqSignIn, context.RepoAssignment(), context.UnitTypes(), reqRepoAdmin, context.RepoRef()) | ||||
| m.Post("/:username/:reponame/action/:action", reqSignIn, context.RepoAssignment(), context.UnitTypes(), repo.Action) | m.Post("/:username/:reponame/action/:action", reqSignIn, context.RepoAssignment(), context.UnitTypes(), repo.Action) | ||||
| m.Get("/tool/query_user_static_page", adminReq, repo.QueryUserStaticDataPage) | |||||
| // Grouping for those endpoints not requiring authentication | // Grouping for those endpoints not requiring authentication | ||||
| m.Group("/:username/:reponame", func() { | m.Group("/:username/:reponame", func() { | ||||
| m.Get("/contributors", repo.Contributors) | m.Get("/contributors", repo.Contributors) | ||||
| @@ -954,29 +960,48 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
| }, context.RepoRef()) | }, context.RepoRef()) | ||||
| m.Group("/cloudbrain", func() { | m.Group("/cloudbrain", func() { | ||||
| m.Get("", reqRepoCloudBrainReader, repo.CloudBrainIndex) | |||||
| m.Group("/:jobid", func() { | m.Group("/:jobid", func() { | ||||
| m.Get("", reqRepoCloudBrainReader, repo.CloudBrainShow) | m.Get("", reqRepoCloudBrainReader, repo.CloudBrainShow) | ||||
| m.Get("/debug", reqRepoCloudBrainReader, repo.CloudBrainDebug) | |||||
| m.Post("/commit_image", reqRepoCloudBrainWriter, bindIgnErr(auth.CommitImageCloudBrainForm{}), repo.CloudBrainCommitImage) | |||||
| m.Post("/stop", reqRepoCloudBrainWriter, repo.CloudBrainStop) | |||||
| m.Post("/del", reqRepoCloudBrainWriter, repo.CloudBrainDel) | |||||
| m.Get("/debug", reqRepoCloudBrainWriter, repo.CloudBrainDebug) | |||||
| m.Post("/commit_image", cloudbrain.AdminOrOwnerOrJobCreaterRight, bindIgnErr(auth.CommitImageCloudBrainForm{}), repo.CloudBrainCommitImage) | |||||
| m.Post("/stop", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.CloudBrainStop) | |||||
| m.Post("/del", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.CloudBrainDel) | |||||
| m.Get("/rate", reqRepoCloudBrainReader, repo.GetRate) | m.Get("/rate", reqRepoCloudBrainReader, repo.GetRate) | ||||
| m.Get("/models", reqRepoCloudBrainReader, repo.CloudBrainShowModels) | m.Get("/models", reqRepoCloudBrainReader, repo.CloudBrainShowModels) | ||||
| m.Get("/download_model", reqRepoCloudBrainReader, repo.CloudBrainDownloadModel) | |||||
| m.Get("/download_model", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.CloudBrainDownloadModel) | |||||
| }) | }) | ||||
| m.Get("/create", reqRepoCloudBrainReader, repo.CloudBrainNew) | |||||
| m.Get("/create", reqRepoCloudBrainWriter, repo.CloudBrainNew) | |||||
| m.Post("/create", reqRepoCloudBrainWriter, bindIgnErr(auth.CreateCloudBrainForm{}), repo.CloudBrainCreate) | m.Post("/create", reqRepoCloudBrainWriter, bindIgnErr(auth.CreateCloudBrainForm{}), repo.CloudBrainCreate) | ||||
| }, context.RepoRef()) | }, context.RepoRef()) | ||||
| m.Group("/modelmanage", func() { | |||||
| m.Post("/create_model", reqRepoModelManageWriter, repo.SaveModel) | |||||
| m.Delete("/delete_model", repo.DeleteModel) | |||||
| m.Put("/modify_model", repo.ModifyModelInfo) | |||||
| m.Get("/show_model", reqRepoModelManageReader, repo.ShowModelTemplate) | |||||
| m.Get("/show_model_info", repo.ShowModelInfo) | |||||
| m.Get("/show_model_info_api", repo.ShowSingleModel) | |||||
| m.Get("/show_model_api", repo.ShowModelPageInfo) | |||||
| m.Get("/show_model_child_api", repo.ShowOneVersionOtherModel) | |||||
| m.Get("/query_train_job", reqRepoCloudBrainReader, repo.QueryTrainJobList) | |||||
| m.Get("/query_train_job_version", reqRepoCloudBrainReader, repo.QueryTrainJobVersionList) | |||||
| m.Group("/:ID", func() { | |||||
| m.Get("", repo.ShowSingleModel) | |||||
| m.Get("/downloadsingle", repo.DownloadSingleModelFile) | |||||
| }) | |||||
| m.Get("/downloadall", repo.DownloadMultiModelFile) | |||||
| }, context.RepoRef()) | |||||
| m.Group("/debugjob", func() { | |||||
| m.Get("", reqRepoCloudBrainReader, repo.DebugJobIndex) | |||||
| }, context.RepoRef()) | |||||
| m.Group("/modelarts", func() { | m.Group("/modelarts", func() { | ||||
| m.Group("/notebook", func() { | m.Group("/notebook", func() { | ||||
| m.Get("", reqRepoCloudBrainReader, repo.NotebookIndex) | |||||
| m.Group("/:jobid", func() { | m.Group("/:jobid", func() { | ||||
| m.Get("", reqRepoCloudBrainReader, repo.NotebookShow) | m.Get("", reqRepoCloudBrainReader, repo.NotebookShow) | ||||
| m.Get("/debug", reqRepoCloudBrainReader, repo.NotebookDebug) | |||||
| m.Post("/stop", reqRepoCloudBrainWriter, repo.NotebookStop) | |||||
| m.Post("/del", reqRepoCloudBrainWriter, repo.NotebookDel) | |||||
| m.Get("/debug", reqRepoCloudBrainWriter, repo.NotebookDebug) | |||||
| m.Post("/stop", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.NotebookStop) | |||||
| m.Post("/del", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.NotebookDel) | |||||
| }) | }) | ||||
| m.Get("/create", reqRepoCloudBrainWriter, repo.NotebookNew) | m.Get("/create", reqRepoCloudBrainWriter, repo.NotebookNew) | ||||
| m.Post("/create", reqRepoCloudBrainWriter, bindIgnErr(auth.CreateModelArtsNotebookForm{}), repo.NotebookCreate) | m.Post("/create", reqRepoCloudBrainWriter, bindIgnErr(auth.CreateModelArtsNotebookForm{}), repo.NotebookCreate) | ||||
| @@ -986,13 +1011,13 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
| m.Get("", reqRepoCloudBrainReader, repo.TrainJobIndex) | m.Get("", reqRepoCloudBrainReader, repo.TrainJobIndex) | ||||
| m.Group("/:jobid", func() { | m.Group("/:jobid", func() { | ||||
| m.Get("", reqRepoCloudBrainReader, repo.TrainJobShow) | m.Get("", reqRepoCloudBrainReader, repo.TrainJobShow) | ||||
| m.Post("/stop", reqRepoCloudBrainWriter, repo.TrainJobStop) | |||||
| m.Post("/del", reqRepoCloudBrainWriter, repo.TrainJobDel) | |||||
| m.Get("/model_download", reqRepoCloudBrainReader, repo.ModelDownload) | |||||
| m.Get("/create_version", reqRepoCloudBrainReader, repo.TrainJobNewVersion) | |||||
| m.Post("/create_version", reqRepoCloudBrainWriter, bindIgnErr(auth.CreateModelArtsTrainJobForm{}), repo.TrainJobCreateVersion) | |||||
| m.Post("/stop", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.TrainJobStop) | |||||
| m.Post("/del", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.TrainJobDel) | |||||
| m.Get("/model_download", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.ModelDownload) | |||||
| m.Get("/create_version", cloudbrain.AdminOrJobCreaterRight, repo.TrainJobNewVersion) | |||||
| m.Post("/create_version", cloudbrain.AdminOrJobCreaterRight, bindIgnErr(auth.CreateModelArtsTrainJobForm{}), repo.TrainJobCreateVersion) | |||||
| }) | }) | ||||
| m.Get("/create", reqRepoCloudBrainReader, repo.TrainJobNew) | |||||
| m.Get("/create", reqRepoCloudBrainWriter, repo.TrainJobNew) | |||||
| m.Post("/create", reqRepoCloudBrainWriter, bindIgnErr(auth.CreateModelArtsTrainJobForm{}), repo.TrainJobCreate) | m.Post("/create", reqRepoCloudBrainWriter, bindIgnErr(auth.CreateModelArtsTrainJobForm{}), repo.TrainJobCreate) | ||||
| m.Get("/para-config-list", reqRepoCloudBrainReader, repo.TrainJobGetConfigList) | m.Get("/para-config-list", reqRepoCloudBrainReader, repo.TrainJobGetConfigList) | ||||
| @@ -6,6 +6,7 @@ | |||||
| package user | package user | ||||
| import ( | import ( | ||||
| "errors" | |||||
| "fmt" | "fmt" | ||||
| "path" | "path" | ||||
| "strings" | "strings" | ||||
| @@ -103,10 +104,47 @@ func Profile(ctx *context.Context) { | |||||
| return | return | ||||
| } | } | ||||
| for _, org := range orgs { | |||||
| _, repoCount, err := models.SearchRepository(&models.SearchRepoOptions{ | |||||
| OwnerID: org.ID, | |||||
| Private: ctx.IsSigned, | |||||
| Actor: ctx.User, | |||||
| }) | |||||
| if err != nil { | |||||
| ctx.ServerError("SearchRepository", err) | |||||
| return | |||||
| } | |||||
| var opts = models.FindOrgMembersOpts{ | |||||
| OrgID: org.ID, | |||||
| PublicOnly: true, | |||||
| } | |||||
| if ctx.User != nil { | |||||
| isMember, err := org.IsOrgMember(ctx.User.ID) | |||||
| if err != nil { | |||||
| ctx.Error(500, "IsOrgMember") | |||||
| return | |||||
| } | |||||
| opts.PublicOnly = !isMember && !ctx.User.IsAdmin | |||||
| } | |||||
| membersCount, err := models.CountOrgMembers(opts) | |||||
| if err != nil { | |||||
| ctx.ServerError("CountOrgMembers", err) | |||||
| return | |||||
| } | |||||
| org.NumMembers = int(membersCount) | |||||
| org.NumRepos = int(repoCount) | |||||
| } | |||||
| ctx.Data["Orgs"] = orgs | ctx.Data["Orgs"] = orgs | ||||
| ctx.Data["HasOrgsVisible"] = models.HasOrgsVisible(orgs, ctx.User) | ctx.Data["HasOrgsVisible"] = models.HasOrgsVisible(orgs, ctx.User) | ||||
| tab := ctx.Query("tab") | tab := ctx.Query("tab") | ||||
| if tab == "" { | |||||
| tab = "activity" | |||||
| } | |||||
| ctx.Data["TabName"] = tab | ctx.Data["TabName"] = tab | ||||
| page := ctx.QueryInt("page") | page := ctx.QueryInt("page") | ||||
| @@ -210,10 +248,15 @@ func Profile(ctx *context.Context) { | |||||
| total = int(count) | total = int(count) | ||||
| case "datasets": | case "datasets": | ||||
| var isOwner = false | |||||
| if ctx.User != nil && ctx.User.ID == ctxUser.ID { | |||||
| isOwner = true | |||||
| } | |||||
| datasetSearchOptions := &models.SearchDatasetOptions{ | datasetSearchOptions := &models.SearchDatasetOptions{ | ||||
| Keyword: keyword, | Keyword: keyword, | ||||
| OwnerID: ctxUser.ID, | OwnerID: ctxUser.ID, | ||||
| SearchOrderBy: orderBy, | SearchOrderBy: orderBy, | ||||
| IsOwner: isOwner, | |||||
| ListOptions: models.ListOptions{ | ListOptions: models.ListOptions{ | ||||
| Page: page, | Page: page, | ||||
| PageSize: setting.UI.ExplorePagingNum, | PageSize: setting.UI.ExplorePagingNum, | ||||
| @@ -230,7 +273,7 @@ func Profile(ctx *context.Context) { | |||||
| } | } | ||||
| total = int(count) | total = int(count) | ||||
| ctx.Data["Datasets"] = datasets | ctx.Data["Datasets"] = datasets | ||||
| default: | |||||
| case "repository": | |||||
| repos, count, err = models.SearchRepository(&models.SearchRepoOptions{ | repos, count, err = models.SearchRepository(&models.SearchRepoOptions{ | ||||
| ListOptions: models.ListOptions{ | ListOptions: models.ListOptions{ | ||||
| PageSize: setting.UI.User.RepoPagingNum, | PageSize: setting.UI.User.RepoPagingNum, | ||||
| @@ -251,6 +294,9 @@ func Profile(ctx *context.Context) { | |||||
| } | } | ||||
| total = int(count) | total = int(count) | ||||
| default: | |||||
| ctx.ServerError("tab error", errors.New("tab error")) | |||||
| return | |||||
| } | } | ||||
| ctx.Data["Repos"] = repos | ctx.Data["Repos"] = repos | ||||
| ctx.Data["Total"] = total | ctx.Data["Total"] = total | ||||
| @@ -17,47 +17,63 @@ | |||||
| {{if .IsSigned}} | {{if .IsSigned}} | ||||
| <a class="item {{if .PageIsDashboard}}active{{end}}" href="/dashboard">{{.i18n.Tr "index"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi"}}</a> | |||||
| {{if not .UnitIssuesGlobalDisabled}} | |||||
| <a class="item {{if .PageIsIssues}}active{{end}}" href="{{AppSubUrl}}/issues">{{.i18n.Tr "issues"}}</a> | |||||
| {{end}} | |||||
| {{if not .UnitPullsGlobalDisabled}} | |||||
| <a class="item {{if .PageIsPulls}}active{{end}}" href="{{AppSubUrl}}/pulls">{{.i18n.Tr "pull_requests"}}</a> | |||||
| {{end}} | |||||
| {{if not (and .UnitIssuesGlobalDisabled .UnitPullsGlobalDisabled)}} | |||||
| {{if .ShowMilestonesDashboardPage}}<a class="item {{if .PageIsMilestonesDashboard}}active{{end}}" href="{{AppSubUrl}}/milestones">{{.i18n.Tr "milestones"}}</a>{{end}} | |||||
| {{end}} | |||||
| <div class="ui dropdown item"> | |||||
| <div class=" item edge"> | |||||
| <div class="dropdown-menu"> | |||||
| <a class=" item lfpd" href="/dashboard" > | |||||
| {{.i18n.Tr "index"}} <i class="dropdown icon mglf" ></i> | |||||
| </a> | |||||
| <div class="dropdown-content" style="min-width: 110px;border-radius:4px"> | |||||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/issues">{{.i18n.Tr "issues"}}</a> | |||||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/pulls">{{.i18n.Tr "pull_requests"}}</a> | |||||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/milestones">{{.i18n.Tr "milestones"}}</a> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | |||||
| <div class="ui dropdown item" id='dropdown_explore'> | |||||
| {{.i18n.Tr "explore"}} | {{.i18n.Tr "explore"}} | ||||
| <i class="dropdown icon"></i> | <i class="dropdown icon"></i> | ||||
| <div class="menu"> | <div class="menu"> | ||||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a> | ||||
| <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | ||||
| <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | ||||
| {{if .IsAdmin}} | |||||
| {{if .IsOperator}} | |||||
| <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> | ||||
| {{end}} | |||||
| {{end}} | |||||
| <a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi"}}</a> | |||||
| </div> | </div> | ||||
| </div> | |||||
| </div> | |||||
| {{else if .IsLandingPageHome}} | {{else if .IsLandingPageHome}} | ||||
| <a class="item {{if .PageIsHome}}active{{end}}" href="{{AppSubUrl}}/dashboard">{{.i18n.Tr "home"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi"}}</a> | |||||
| <div class="item edge"> | |||||
| <div class="dropdown-menu"> | |||||
| <a class=" item lfpd" href="/user/login"> | |||||
| {{.i18n.Tr "home"}} <i class="dropdown icon mglf"></i> | |||||
| </a> | |||||
| <div class="dropdown-content" style="min-width: 110px;border-radius:4px"> | |||||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "issues"}}</a> | |||||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "pull_requests"}}</a> | |||||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "milestones"}}</a> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div class="ui dropdown item"> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | |||||
| <div class="ui dropdown item" id='dropdown_PageHome'> | |||||
| {{.i18n.Tr "explore"}} | {{.i18n.Tr "explore"}} | ||||
| <i class="dropdown icon"></i> | <i class="dropdown icon"></i> | ||||
| <div class="menu"> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "datasets"}}</a> | |||||
| <div class="menu" > | |||||
| <a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a> | ||||
| <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | ||||
| <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | ||||
| {{if .IsAdmin}} | |||||
| {{if .IsOperator}} | |||||
| <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> | ||||
| {{end}} | {{end}} | ||||
| <a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi"}}</a> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| {{else if .IsLandingPageExplore}} | {{else if .IsLandingPageExplore}} | ||||
| @@ -78,7 +94,18 @@ | |||||
| */}} | */}} | ||||
| {{if .IsSigned}} | {{if .IsSigned}} | ||||
| <div class="right stackable menu"> | |||||
| <div class="right stackable menu"> | |||||
| <form class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/explore/repos"> | |||||
| <div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;"> | |||||
| <input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search_pro"}}..." | |||||
| style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;"> | |||||
| <input type="hidden" name="tab" value="{{$.TabName}}"> | |||||
| <input type="hidden" name="sort" value="hot"> | |||||
| <button style="border: none;background-color: #363840;outline: none;border-radius:5px"><img type = "submit" style="width: 25px; height: 25px;margin: auto;" src="/img/search.svg" > | |||||
| </button> | |||||
| <!-- <button class="ui green button">{{.i18n.Tr "explore.search"}}</button> --> | |||||
| </div> | |||||
| </form> | |||||
| <a href="{{AppSubUrl}}/notifications" class="item poping up" data-content='{{.i18n.Tr "notifications"}}' data-variation="tiny inverted"> | <a href="{{AppSubUrl}}/notifications" class="item poping up" data-content='{{.i18n.Tr "notifications"}}' data-variation="tiny inverted"> | ||||
| <span class="text"> | <span class="text"> | ||||
| <span class="fitted">{{svg "octicon-bell" 16}}</span> | <span class="fitted">{{svg "octicon-bell" 16}}</span> | ||||
| @@ -163,6 +190,18 @@ | |||||
| <!--a class="item" target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io">{{.i18n.Tr "help"}}</a--> | <!--a class="item" target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io">{{.i18n.Tr "help"}}</a--> | ||||
| <div class="right stackable menu"> | <div class="right stackable menu"> | ||||
| <form class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/explore/repos"> | |||||
| <div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;"> | |||||
| <input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search_pro"}}..." | |||||
| style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;"> | |||||
| <input type="hidden" name="tab" value="{{$.TabName}}"> | |||||
| <input type="hidden" name="sort" value="hot"> | |||||
| <button style="border: none;background-color: #363840;outline: none;border-radius:5px"><img type = "submit" style="width: 25px; height: 25px;margin: auto;" src="/img/search.svg" > | |||||
| </button> | |||||
| <!-- <button class="ui green button">{{.i18n.Tr "explore.search"}}</button> --> | |||||
| </div> | |||||
| </form> | |||||
| {{if .ShowRegistrationButton}} | {{if .ShowRegistrationButton}} | ||||
| <a class="item{{if .PageIsSignUp}} active{{end}}" href="{{AppSubUrl}}/user/sign_up"> | <a class="item{{if .PageIsSignUp}} active{{end}}" href="{{AppSubUrl}}/user/sign_up"> | ||||
| {{svg "octicon-person" 16}} {{.i18n.Tr "register"}} | {{svg "octicon-person" 16}} {{.i18n.Tr "register"}} | ||||
| @@ -17,47 +17,61 @@ | |||||
| {{if .IsSigned}} | {{if .IsSigned}} | ||||
| <a class="item {{if .PageIsDashboard}}active{{end}}" href="/dashboard">{{.i18n.Tr "index"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi"}}</a> | |||||
| {{if not .UnitIssuesGlobalDisabled}} | |||||
| <a class="item {{if .PageIsIssues}}active{{end}}" href="{{AppSubUrl}}/issues">{{.i18n.Tr "issues"}}</a> | |||||
| {{end}} | |||||
| {{if not .UnitPullsGlobalDisabled}} | |||||
| <a class="item {{if .PageIsPulls}}active{{end}}" href="{{AppSubUrl}}/pulls">{{.i18n.Tr "pull_requests"}}</a> | |||||
| {{end}} | |||||
| {{if not (and .UnitIssuesGlobalDisabled .UnitPullsGlobalDisabled)}} | |||||
| {{if .ShowMilestonesDashboardPage}}<a class="item {{if .PageIsMilestonesDashboard}}active{{end}}" href="{{AppSubUrl}}/milestones">{{.i18n.Tr "milestones"}}</a>{{end}} | |||||
| {{end}} | |||||
| <div class="ui dropdown item"> | |||||
| <div class="item edge" > | |||||
| <div class="dropdown-menu"> | |||||
| <a class=" item lfpd" href="/dashboard"> | |||||
| {{.i18n.Tr "index"}} <i class="dropdown icon mglf"></i> | |||||
| </a> | |||||
| <div class="dropdown-content" style="min-width: 110px;border-radius:4px"> | |||||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/issues">{{.i18n.Tr "issues"}}</a> | |||||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/pulls">{{.i18n.Tr "pull_requests"}}</a> | |||||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/milestones">{{.i18n.Tr "milestones"}}</a> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | |||||
| <div class="ui dropdown item" id='dropdown_explore'> | |||||
| {{.i18n.Tr "explore"}} | {{.i18n.Tr "explore"}} | ||||
| <i class="dropdown icon"></i> | <i class="dropdown icon"></i> | ||||
| <div class="menu"> | <div class="menu"> | ||||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a> | ||||
| <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | ||||
| <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | ||||
| {{if .IsAdmin}} | |||||
| {{if .IsOperator}} | |||||
| <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> | ||||
| {{end}} | |||||
| {{end}} | |||||
| <a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi"}}</a> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| {{else if .IsLandingPageHome}} | {{else if .IsLandingPageHome}} | ||||
| <a class="item {{if .PageIsHome}}active{{end}}" href="{{AppSubUrl}}/dashboard">{{.i18n.Tr "home"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi"}}</a> | |||||
| <div class="ui dropdown item"> | |||||
| <div class="item edge" > | |||||
| <div class="dropdown-menu"> | |||||
| <a class=" item lfpd" href="/user/login"> | |||||
| {{.i18n.Tr "home"}} <i class="dropdown icon mglf"></i> | |||||
| </a> | |||||
| <div class="dropdown-content" style="min-width: 110px;border-radius:4px"> | |||||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "issues"}}</a> | |||||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "pull_requests"}}</a> | |||||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "milestones"}}</a> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | |||||
| <div class="ui dropdown item" id='dropdown_PageHome'> | |||||
| {{.i18n.Tr "explore"}} | {{.i18n.Tr "explore"}} | ||||
| <i class="dropdown icon"></i> | <i class="dropdown icon"></i> | ||||
| <div class="menu"> | <div class="menu"> | ||||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "datasets"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a> | ||||
| <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | ||||
| <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | ||||
| {{if .IsAdmin}} | |||||
| {{if .IsOperator}} | |||||
| <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> | ||||
| {{end}} | {{end}} | ||||
| <a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi"}}</a> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| {{else if .IsLandingPageExplore}} | {{else if .IsLandingPageExplore}} | ||||
| @@ -79,6 +93,17 @@ | |||||
| {{if .IsSigned}} | {{if .IsSigned}} | ||||
| <div class="right stackable menu"> | <div class="right stackable menu"> | ||||
| <form class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/explore/repos"> | |||||
| <div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;"> | |||||
| <input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search_pro"}}..." | |||||
| style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;"> | |||||
| <input type="hidden" name="tab" value="{{$.TabName}}"> | |||||
| <input type="hidden" name="sort" value="{{$.SortType}}"> | |||||
| <button style="border: none;background-color: #363840;outline: none;border-radius:5px"><img type = "submit" style="width: 25px; height: 25px;margin: auto;" src="/img/search.svg" > | |||||
| </button> | |||||
| <!-- <button class="ui green button">{{.i18n.Tr "explore.search"}}</button> --> | |||||
| </div> | |||||
| </form> | |||||
| <a href="{{AppSubUrl}}/notifications" class="item poping up" data-content='{{.i18n.Tr "notifications"}}' data-variation="tiny inverted"> | <a href="{{AppSubUrl}}/notifications" class="item poping up" data-content='{{.i18n.Tr "notifications"}}' data-variation="tiny inverted"> | ||||
| <span class="text"> | <span class="text"> | ||||
| <span class="fitted">{{svg "octicon-bell" 16}}</span> | <span class="fitted">{{svg "octicon-bell" 16}}</span> | ||||
| @@ -163,6 +188,17 @@ | |||||
| <!--a class="item" target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io">{{.i18n.Tr "help"}}</a--> | <!--a class="item" target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io">{{.i18n.Tr "help"}}</a--> | ||||
| <div class="right stackable menu"> | <div class="right stackable menu"> | ||||
| <form class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/explore/repos"> | |||||
| <div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;"> | |||||
| <input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search_pro"}}..." | |||||
| style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;"> | |||||
| <input type="hidden" name="tab" value="{{$.TabName}}"> | |||||
| <input type="hidden" name="sort" value="{{$.SortType}}"> | |||||
| <button style="border: none;background-color: #363840;outline: none;border-radius:5px"><img type = "submit" style="width: 25px; height: 25px;margin: auto;" src="/img/search.svg" > | |||||
| </button> | |||||
| <!-- <button class="ui green button">{{.i18n.Tr "explore.search"}}</button> --> | |||||
| </div> | |||||
| </form> | |||||
| {{if .ShowRegistrationButton}} | {{if .ShowRegistrationButton}} | ||||
| <a class="item{{if .PageIsSignUp}} active{{end}}" href="{{AppSubUrl}}/user/sign_up"> | <a class="item{{if .PageIsSignUp}} active{{end}}" href="{{AppSubUrl}}/user/sign_up"> | ||||
| {{svg "octicon-person" 16}} {{.i18n.Tr "register"}} | {{svg "octicon-person" 16}} {{.i18n.Tr "register"}} | ||||
| @@ -9,47 +9,62 @@ | |||||
| </div> | </div> | ||||
| {{if .IsSigned}} | {{if .IsSigned}} | ||||
| <a class="item {{if .PageIsDashboard}}active{{end}}" href="/dashboard">{{.i18n.Tr "index"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi"}}</a> | |||||
| {{if not .UnitIssuesGlobalDisabled}} | |||||
| <a class="item {{if .PageIsIssues}}active{{end}}" href="{{AppSubUrl}}/issues">{{.i18n.Tr "issues"}}</a> | |||||
| {{end}} | |||||
| {{if not .UnitPullsGlobalDisabled}} | |||||
| <a class="item {{if .PageIsPulls}}active{{end}}" href="{{AppSubUrl}}/pulls">{{.i18n.Tr "pull_requests"}}</a> | |||||
| {{end}} | |||||
| {{if not (and .UnitIssuesGlobalDisabled .UnitPullsGlobalDisabled)}} | |||||
| {{if .ShowMilestonesDashboardPage}}<a class="item {{if .PageIsMilestonesDashboard}}active{{end}}" href="{{AppSubUrl}}/milestones">{{.i18n.Tr "milestones"}}</a>{{end}} | |||||
| {{end}} | |||||
| <div class="ui dropdown item"> | |||||
| <div class="item edge" > | |||||
| <div class="dropdown-menu"> | |||||
| <a class=" item lfpd" href="/dashboard"> | |||||
| {{.i18n.Tr "index"}} <i class="dropdown icon mglf"></i> | |||||
| </a> | |||||
| <div class="dropdown-content" style="min-width: 110px;border-radius:4px"> | |||||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/issues">{{.i18n.Tr "issues"}}</a> | |||||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/pulls">{{.i18n.Tr "pull_requests"}}</a> | |||||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/milestones">{{.i18n.Tr "milestones"}}</a> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | |||||
| <div class="ui dropdown item" id='dropdown_explore'> | |||||
| {{.i18n.Tr "explore"}} | {{.i18n.Tr "explore"}} | ||||
| <i class="dropdown icon"></i> | <i class="dropdown icon"></i> | ||||
| <div class="menu"> | <div class="menu"> | ||||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a> | ||||
| <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | ||||
| <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | ||||
| {{if .IsAdmin}} | |||||
| {{if .IsOperator}} | |||||
| <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> | ||||
| {{end}} | |||||
| {{end}} | |||||
| <a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi"}}</a> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| {{else if .IsLandingPageHome}} | {{else if .IsLandingPageHome}} | ||||
| <a class="item {{if .PageIsHome}}active{{end}}" href="{{AppSubUrl}}/dashboard">{{.i18n.Tr "home"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi"}}</a> | |||||
| <div class="item edge" > | |||||
| <div class="dropdown-menu"> | |||||
| <a class=" item lfpd" href="/user/login"> | |||||
| {{.i18n.Tr "home"}} <i class="dropdown icon mglf"></i> | |||||
| </a> | |||||
| <div class="dropdown-content" style="min-width: 110px;border-radius:4px"> | |||||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "issues"}}</a> | |||||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "pull_requests"}}</a> | |||||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "milestones"}}</a> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div class="ui dropdown item"> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | |||||
| <div class="ui dropdown item" id='dropdown_PageHome'> | |||||
| {{.i18n.Tr "explore"}} | {{.i18n.Tr "explore"}} | ||||
| <i class="dropdown icon"></i> | <i class="dropdown icon"></i> | ||||
| <div class="menu"> | <div class="menu"> | ||||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "datasets"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a> | ||||
| <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | ||||
| <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | ||||
| {{if .IsAdmin}} | |||||
| {{if .IsOperator}} | |||||
| <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> | <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> | ||||
| {{end}} | {{end}} | ||||
| <a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi"}}</a> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| {{else if .IsLandingPageExplore}} | {{else if .IsLandingPageExplore}} | ||||
| @@ -0,0 +1,216 @@ | |||||
| <div class="ui container" id="navbar"> | |||||
| <div class="item brand" style="justify-content: space-between;"> | |||||
| <a href="https://openi.org.cn/"> | |||||
| <img class="ui mini image" src="{{StaticUrlPrefix}}/img/logo-w.svg"> | |||||
| </a> | |||||
| <div class="ui basic icon button mobile-only" id="navbar-expand-toggle"> | |||||
| <i class="sidebar icon"></i> | |||||
| </div> | |||||
| </div> | |||||
| <div style="width:1px;background:#606266;height:80%;margin:auto 0.5rem"></div> | |||||
| <div class="item brand" style="margin-left: 0.9rem;"> | |||||
| <a href="/"> | |||||
| <img class="ui mini image" style="height: 1.3rem;" src="{{StaticUrlPrefix}}/img/git-logo.svg"> | |||||
| </a> | |||||
| </div> | |||||
| {{if .IsSigned}} | |||||
| <div class=" item edge" > | |||||
| <div class="dropdown-menu"> | |||||
| <a class=" item lfpd" href="/dashboard"> | |||||
| {{.i18n.Tr "index"}} <i class="dropdown icon mglf"></i> | |||||
| </a> | |||||
| <div class="dropdown-content" style="min-width: 110px;border-radius:4px"> | |||||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/issues">{{.i18n.Tr "issues"}}</a> | |||||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/pulls">{{.i18n.Tr "pull_requests"}}</a> | |||||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/milestones">{{.i18n.Tr "milestones"}}</a> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | |||||
| <div class="ui dropdown item" id='dropdown_explore'> | |||||
| {{.i18n.Tr "explore"}} | |||||
| <i class="dropdown icon"></i> | |||||
| <div class="menu"> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | |||||
| {{if .IsOperator}} | |||||
| <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> | |||||
| {{end}} | |||||
| <a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi"}}</a> | |||||
| </div> | |||||
| </div> | |||||
| {{else if .IsLandingPageHome}} | |||||
| <div class="item edge"> | |||||
| <div class="dropdown-menu"> | |||||
| <a class=" item" href="/user/login"> | |||||
| {{.i18n.Tr "home"}} <i class="dropdown icon mglf"></i> | |||||
| </a> | |||||
| <div class="dropdown-content" style="min-width: 110px;border-radius:4px"> | |||||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "issues"}}</a> | |||||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "pull_requests"}}</a> | |||||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "milestones"}}</a> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | |||||
| <div class="ui dropdown item" id='dropdown_PageHome'> | |||||
| {{.i18n.Tr "explore"}} | |||||
| <i class="dropdown icon"></i> | |||||
| <div class="menu" > | |||||
| <a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | |||||
| <a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | |||||
| {{if .IsOperator}} | |||||
| <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> | |||||
| {{end}} | |||||
| <a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi"}}</a> | |||||
| </div> | |||||
| </div> | |||||
| {{else if .IsLandingPageExplore}} | |||||
| <a class="item {{if .PageIsExplore}}active{{end}}" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "home"}}</a> | |||||
| {{else if .IsLandingPageOrganizations}} | |||||
| <a class="item {{if .PageIsExplore}}active{{end}}" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "home"}}</a> | |||||
| {{end}} | |||||
| {{template "custom/extra_links" .}} | |||||
| {{/* | |||||
| <div class="item"> | |||||
| <div class="ui icon input"> | |||||
| <input class="searchbox" type="text" placeholder="{{.i18n.Tr "search_project"}}"> | |||||
| <i class="search icon"></i> | |||||
| </div> | |||||
| </div> | |||||
| */}} | |||||
| {{if .IsSigned}} | |||||
| <div class="right stackable menu"> | |||||
| <form class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/explore/repos"> | |||||
| <div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;"> | |||||
| <input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search_pro"}}..." | |||||
| style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;"> | |||||
| <input type="hidden" name="tab" value="{{$.TabName}}"> | |||||
| <input type="hidden" name="sort" value="{{$.SortType}}"> | |||||
| <button style="border: none;background-color: #363840;outline: none;border-radius:5px"><img type = "submit" style="width: 25px; height: 25px;margin: auto;" src="/img/search.svg" > | |||||
| </button> | |||||
| <!-- <button class="ui green button">{{.i18n.Tr "explore.search"}}</button> --> | |||||
| </div> | |||||
| </form> | |||||
| <a href="{{AppSubUrl}}/notifications" class="item poping up" data-content='{{.i18n.Tr "notifications"}}' data-variation="tiny inverted"> | |||||
| <span class="text"> | |||||
| <span class="fitted">{{svg "octicon-bell" 16}}</span> | |||||
| <span class="sr-mobile-only">{{.i18n.Tr "notifications"}}</span> | |||||
| {{$notificationUnreadCount := 0}} | |||||
| {{if .NotificationUnreadCount}}{{$notificationUnreadCount = call .NotificationUnreadCount}}{{end}} | |||||
| <span class="ui red label {{if not $notificationUnreadCount}}hidden{{end}} notification_count"> | |||||
| {{$notificationUnreadCount}} | |||||
| </span> | |||||
| </span> | |||||
| </a> | |||||
| <div class="ui dropdown jump item poping up" data-content="{{.i18n.Tr "create_new"}}" data-variation="tiny inverted"> | |||||
| <span class="text"> | |||||
| <span class="fitted">{{svg "octicon-plus" 16}}</span> | |||||
| <span class="sr-mobile-only">{{.i18n.Tr "create_new"}}</span> | |||||
| <span class="fitted not-mobile">{{svg "octicon-triangle-down" 16}}</span> | |||||
| </span> | |||||
| <div class="menu"> | |||||
| <a class="item" href="{{AppSubUrl}}/repo/create"> | |||||
| <span class="fitted">{{svg "octicon-plus" 16}}</span> {{.i18n.Tr "new_repo"}} | |||||
| </a> | |||||
| <a class="item" href="{{AppSubUrl}}/repo/migrate"> | |||||
| <span class="fitted">{{svg "octicon-repo-clone" 16}}</span> {{.i18n.Tr "new_migrate"}} | |||||
| </a> | |||||
| {{if .SignedUser.CanCreateOrganization}} | |||||
| <a class="item" href="{{AppSubUrl}}/org/create"> | |||||
| <span class="fitted">{{svg "octicon-organization" 16}}</span> {{.i18n.Tr "new_org"}} | |||||
| </a> | |||||
| {{end}} | |||||
| </div><!-- end content create new menu --> | |||||
| </div><!-- end dropdown menu create new --> | |||||
| <div class="ui dropdown jump item poping up" tabindex="-1" data-content="{{.i18n.Tr "user_profile_and_more"}}" data-variation="tiny inverted"> | |||||
| <span class="text"> | |||||
| <img class="ui tiny avatar image" width="24" height="24" src="{{.SignedUser.RelAvatarLink}}"> | |||||
| <span class="sr-only">{{.i18n.Tr "user_profile_and_more"}}</span> | |||||
| <span class="mobile-only">{{.SignedUser.Name}}</span> | |||||
| <span class="fitted not-mobile" tabindex="-1">{{svg "octicon-triangle-down" 16}}</span> | |||||
| </span> | |||||
| <div class="menu user-menu" tabindex="-1"> | |||||
| <div class="ui header"> | |||||
| {{.i18n.Tr "signed_in_as"}} <strong>{{.SignedUser.Name}}</strong> | |||||
| </div> | |||||
| <div class="divider"></div> | |||||
| <a class="item" href="{{AppSubUrl}}/{{.SignedUser.Name}}"> | |||||
| {{svg "octicon-person" 16}} | |||||
| {{.i18n.Tr "your_profile"}}<!-- Your profile --> | |||||
| </a> | |||||
| <a class="item" href="{{AppSubUrl}}/{{.SignedUser.Name}}?tab=stars"> | |||||
| {{svg "octicon-star" 16}} | |||||
| {{.i18n.Tr "your_starred"}} | |||||
| </a> | |||||
| <a class="{{if .PageIsUserSettings}}active{{end}} item" href="{{AppSubUrl}}/user/settings"> | |||||
| {{svg "octicon-settings" 16}} | |||||
| {{.i18n.Tr "your_settings"}}<!-- Your settings --> | |||||
| </a> | |||||
| <!--a class="item" target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io"> | |||||
| {{svg "octicon-question" 16}} | |||||
| {{.i18n.Tr "help"}}<!-- Help --> | |||||
| </a--> | |||||
| {{if .IsAdmin}} | |||||
| <div class="divider"></div> | |||||
| <a class="{{if .PageIsAdmin}}active{{end}} item" href="{{AppSubUrl}}/admin"> | |||||
| <i class="icon settings"></i> | |||||
| {{.i18n.Tr "admin_panel"}}<!-- Admin Panel --> | |||||
| </a> | |||||
| {{end}} | |||||
| <div class="divider"></div> | |||||
| <a class="item link-action" href data-url="{{AppSubUrl}}/user/logout" data-redirect="{{AppSubUrl}}/"> | |||||
| {{svg "octicon-sign-out" 16}} | |||||
| {{.i18n.Tr "sign_out"}}<!-- Sign Out --> | |||||
| </a> | |||||
| </div><!-- end content avatar menu --> | |||||
| </div><!-- end dropdown avatar menu --> | |||||
| </div><!-- end signed user right menu --> | |||||
| {{else}} | |||||
| <!--a class="item" target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io">{{.i18n.Tr "help"}}</a--> | |||||
| <div class="right stackable menu"> | |||||
| <form class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/explore/repos"> | |||||
| <div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;"> | |||||
| <input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search_pro"}}..." | |||||
| style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;"> | |||||
| <input type="hidden" name="tab" value="{{$.TabName}}"> | |||||
| <input type="hidden" name="sort" value="{{$.SortType}}"> | |||||
| <button style="border: none;background-color: #363840;outline: none;border-radius:5px"><img type = "submit" style="width: 25px; height: 25px;margin: auto;" src="/img/search.svg" > | |||||
| </button> | |||||
| <!-- <button class="ui green button">{{.i18n.Tr "explore.search"}}</button> --> | |||||
| </div> | |||||
| </form> | |||||
| {{if .ShowRegistrationButton}} | |||||
| <a class="item{{if .PageIsSignUp}} active{{end}}" href="{{AppSubUrl}}/user/sign_up"> | |||||
| {{svg "octicon-person" 16}} {{.i18n.Tr "register"}} | |||||
| </a> | |||||
| {{end}} | |||||
| <a class="item{{if .PageIsSignIn}} active{{end}}" rel="nofollow" href="{{AppSubUrl}}/user/login"> | |||||
| {{svg "octicon-sign-in" 16}} {{.i18n.Tr "sign_in"}} | |||||
| </a> | |||||
| </div><!-- end anonymous right menu --> | |||||
| {{end}} | |||||
| </div> | |||||
| @@ -0,0 +1,208 @@ | |||||
| <!DOCTYPE html> | |||||
| <html lang="{{.Language}}"> | |||||
| <head data-suburl="{{AppSubUrl}}"> | |||||
| <meta charset="utf-8"> | |||||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||||
| <meta http-equiv="x-ua-compatible" content="ie=edge"> | |||||
| <title>{{if .Title}}{{.Title}} - {{end}} {{if .Repository.Name}}{{.Repository.Name}} - {{end}}{{AppName}}</title> | |||||
| <link rel="manifest" href="{{AppSubUrl}}/manifest.json" crossorigin="use-credentials"> | |||||
| {{if UseServiceWorker}} | |||||
| <script> | |||||
| if ('serviceWorker' in navigator) { | |||||
| navigator.serviceWorker.register('{{AppSubUrl}}/serviceworker.js').then(function(registration) { | |||||
| // Registration was successful | |||||
| console.info('ServiceWorker registration successful with scope: ', registration.scope); | |||||
| }, function(err) { | |||||
| // registration failed :( | |||||
| console.info('ServiceWorker registration failed: ', err); | |||||
| }); | |||||
| } | |||||
| </script> | |||||
| {{else}} | |||||
| <script> | |||||
| if ('serviceWorker' in navigator) { | |||||
| navigator.serviceWorker.getRegistrations().then(function(registrations) { | |||||
| registrations.forEach(function(registration) { | |||||
| registration.unregister(); | |||||
| console.info('ServiceWorker unregistered'); | |||||
| }); | |||||
| }); | |||||
| } | |||||
| </script> | |||||
| {{end}} | |||||
| <meta name="theme-color" content="{{ThemeColorMetaTag}}"> | |||||
| <meta name="author" content="{{if .Repository}}{{.Owner.Name}}{{else}}{{MetaAuthor}}{{end}}" /> | |||||
| <meta name="description" content="{{if .Repository}}{{.Repository.Name}}{{if .Repository.Description}} - {{.Repository.Description}}{{end}}{{else}}{{MetaDescription}}{{end}}" /> | |||||
| <meta name="keywords" content="{{MetaKeywords}}"> | |||||
| <meta name="referrer" content="no-referrer" /> | |||||
| <meta name="_csrf" content="{{.CsrfToken}}" /> | |||||
| {{if .IsSigned}} | |||||
| <meta name="_uid" content="{{.SignedUser.ID}}" /> | |||||
| {{end}} | |||||
| {{if .ContextUser}} | |||||
| <meta name="_context_uid" content="{{.ContextUser.ID}}" /> | |||||
| {{end}} | |||||
| {{if .SearchLimit}} | |||||
| <meta name="_search_limit" content="{{.SearchLimit}}" /> | |||||
| {{end}} | |||||
| {{if .GoGetImport}} | |||||
| <meta name="go-import" content="{{.GoGetImport}} git {{.CloneLink.HTTPS}}"> | |||||
| <meta name="go-source" content="{{.GoGetImport}} _ {{.GoDocDirectory}} {{.GoDocFile}}"> | |||||
| {{end}} | |||||
| <script> | |||||
| {{SafeJS `/* | |||||
| @licstart The following is the entire license notice for the | |||||
| JavaScript code in this page. | |||||
| Copyright (c) 2016 The Gitea Authors | |||||
| Copyright (c) 2015 The Gogs Authors | |||||
| Permission is hereby granted, free of charge, to any person obtaining a copy | |||||
| of this software and associated documentation files (the "Software"), to deal | |||||
| in the Software without restriction, including without limitation the rights | |||||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||||
| copies of the Software, and to permit persons to whom the Software is | |||||
| furnished to do so, subject to the following conditions: | |||||
| The above copyright notice and this permission notice shall be included in | |||||
| all copies or substantial portions of the Software. | |||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |||||
| THE SOFTWARE. | |||||
| --- | |||||
| Licensing information for additional javascript libraries can be found at: | |||||
| {{StaticUrlPrefix}}/vendor/librejs.html | |||||
| @licend The above is the entire license notice | |||||
| for the JavaScript code in this page. | |||||
| */`}} | |||||
| </script> | |||||
| <script> | |||||
| window.config = { | |||||
| AppSubUrl: '{{AppSubUrl}}', | |||||
| StaticUrlPrefix: '{{StaticUrlPrefix}}', | |||||
| csrf: '{{.CsrfToken}}', | |||||
| HighlightJS: {{if .RequireHighlightJS}}true{{else}}false{{end}}, | |||||
| Minicolors: {{if .RequireMinicolors}}true{{else}}false{{end}}, | |||||
| SimpleMDE: {{if .RequireSimpleMDE}}true{{else}}false{{end}}, | |||||
| Tribute: {{if .RequireTribute}}true{{else}}false{{end}}, | |||||
| U2F: {{if .RequireU2F}}true{{else}}false{{end}}, | |||||
| Heatmap: {{if .EnableHeatmap}}true{{else}}false{{end}}, | |||||
| heatmapUser: {{if .HeatmapUser}}'{{.HeatmapUser}}'{{else}}null{{end}}, | |||||
| NotificationSettings: { | |||||
| MinTimeout: {{NotificationSettings.MinTimeout}}, | |||||
| TimeoutStep: {{NotificationSettings.TimeoutStep}}, | |||||
| MaxTimeout: {{NotificationSettings.MaxTimeout}}, | |||||
| EventSourceUpdateTime: {{NotificationSettings.EventSourceUpdateTime}}, | |||||
| }, | |||||
| {{if .RequireTribute}} | |||||
| tributeValues: [ | |||||
| {{ range .Assignees }} | |||||
| {key: '{{.Name}} {{.FullName}}', value: '{{.Name}}', | |||||
| name: '{{.Name}}', fullname: '{{.FullName}}', avatar: '{{.RelAvatarLink}}'}, | |||||
| {{ end }} | |||||
| ], | |||||
| {{end}} | |||||
| }; | |||||
| </script> | |||||
| <link rel="shortcut icon" href="{{StaticUrlPrefix}}/img/favicon.png"> | |||||
| <link rel="mask-icon" href="{{StaticUrlPrefix}}/img/openi-safari.svg" color="#609926"> | |||||
| <link rel="fluid-icon" href="{{StaticUrlPrefix}}/img/gitea-lg.png" title="{{AppName}}"> | |||||
| <link rel="stylesheet" href="{{StaticUrlPrefix}}/vendor/assets/font-awesome/css/font-awesome.min.css"> | |||||
| <link rel="preload" as="font" href="{{StaticUrlPrefix}}/fomantic/themes/default/assets/fonts/icons.woff2" type="font/woff2" crossorigin="anonymous"> | |||||
| <link rel="preload" as="font" href="{{StaticUrlPrefix}}/fomantic/themes/default/assets/fonts/outline-icons.woff2" type="font/woff2" crossorigin="anonymous"> | |||||
| {{if .RequireSimpleMDE}} | |||||
| <link rel="stylesheet" href="{{StaticUrlPrefix}}/vendor/plugins/simplemde/simplemde.min.css"> | |||||
| {{end}} | |||||
| {{if .RequireTribute}} | |||||
| <link rel="stylesheet" href="{{StaticUrlPrefix}}/vendor/plugins/tribute/tribute.css"> | |||||
| {{end}} | |||||
| <link rel="stylesheet" href="{{StaticUrlPrefix}}/fomantic/semantic.min.css?v={{MD5 AppVer}}"> | |||||
| <link rel="stylesheet" href="{{StaticUrlPrefix}}/css/index.css?v={{MD5 AppVer}}"> | |||||
| <noscript> | |||||
| <style> | |||||
| .dropdown:hover > .menu { display: block; } | |||||
| .ui.secondary.menu .dropdown.item > .menu { margin-top: 0; } | |||||
| </style> | |||||
| </noscript> | |||||
| {{if .RequireMinicolors}} | |||||
| <link rel="stylesheet" href="{{StaticUrlPrefix}}/vendor/plugins/jquery.minicolors/jquery.minicolors.css"> | |||||
| {{end}} | |||||
| <style class="list-search-style"></style> | |||||
| {{if .PageIsUserProfile}} | |||||
| <meta property="og:title" content="{{.Owner.Name}}" /> | |||||
| <meta property="og:type" content="profile" /> | |||||
| <meta property="og:image" content="{{.Owner.AvatarLink}}" /> | |||||
| <meta property="og:url" content="{{.Owner.HTMLURL}}" /> | |||||
| {{if .Owner.Description}} | |||||
| <meta property="og:description" content="{{.Owner.Description}}"> | |||||
| {{end}} | |||||
| {{else if .Repository}} | |||||
| {{if .Issue}} | |||||
| <meta property="og:title" content="{{.Issue.Title}}" /> | |||||
| <meta property="og:url" content="{{.Issue.HTMLURL}}" /> | |||||
| {{if .Issue.Content}} | |||||
| <meta property="og:description" content="{{.Issue.Content}}" /> | |||||
| {{end}} | |||||
| {{else}} | |||||
| <meta property="og:title" content="{{.Repository.Name}}" /> | |||||
| <meta property="og:url" content="{{.Repository.HTMLURL}}" /> | |||||
| {{if .Repository.Description}} | |||||
| <meta property="og:description" content="{{.Repository.Description}}" /> | |||||
| {{end}} | |||||
| {{end}} | |||||
| <meta property="og:type" content="object" /> | |||||
| <meta property="og:image" content="{{.Repository.Owner.AvatarLink}}" /> | |||||
| {{else}} | |||||
| <meta property="og:title" content="{{AppName}}"> | |||||
| <meta property="og:type" content="website" /> | |||||
| <meta property="og:image" content="{{StaticUrlPrefix}}/img/gitea-lg.png" /> | |||||
| <meta property="og:url" content="{{AppUrl}}" /> | |||||
| <meta property="og:description" content="{{MetaDescription}}"> | |||||
| {{end}} | |||||
| <meta property="og:site_name" content="{{AppName}}" /> | |||||
| {{if .IsSigned }} | |||||
| {{ if ne .SignedUser.Theme "gitea" }} | |||||
| <link rel="stylesheet" href="{{StaticUrlPrefix}}/css/theme-{{.SignedUser.Theme}}.css?v={{MD5 AppVer}}"> | |||||
| {{end}} | |||||
| {{else if ne DefaultTheme "gitea"}} | |||||
| <link rel="stylesheet" href="{{StaticUrlPrefix}}/css/theme-{{DefaultTheme}}.css?v={{MD5 AppVer}}"> | |||||
| {{end}} | |||||
| {{template "custom/header" .}} | |||||
| <script> | |||||
| var _hmt = _hmt || []; | |||||
| (function() { | |||||
| var hm = document.createElement("script"); | |||||
| hm.src = "https://hm.baidu.com/hm.js?46149a0b61fdeddfe427ff4de63794ba"; | |||||
| var s = document.getElementsByTagName("script")[0]; | |||||
| s.parentNode.insertBefore(hm, s); | |||||
| })(); | |||||
| </script> | |||||
| <script src="/self/func.js" type="text/javascript"></script> | |||||
| </head> | |||||
| <body> | |||||
| {{template "custom/body_outer_pre" .}} | |||||
| <div class="full height"> | |||||
| <noscript>{{.i18n.Tr "enable_javascript"}}</noscript> | |||||
| {{template "custom/body_inner_pre" .}} | |||||
| {{if not .PageIsInstall}} | |||||
| <div class="ui top secondary stackable main menu following bar dark"> | |||||
| {{template "base/head_navbar_pro" .}} | |||||
| </div><!-- end bar --> | |||||
| {{end}} | |||||
| {{/* | |||||
| </div> | |||||
| </body> | |||||
| </html> | |||||
| */}} | |||||
| @@ -1,4 +1,4 @@ | |||||
| {{template "base/head" .}} | |||||
| {{template "base/head_pro" .}} | |||||
| <div class="explore repositories"> | <div class="explore repositories"> | ||||
| {{template "explore/repo_search" .}} | {{template "explore/repo_search" .}} | ||||
| @@ -93,16 +93,6 @@ | |||||
| display: none; | display: none; | ||||
| } | } | ||||
| .select2-container .select2-selection--single{ | |||||
| height:38px !important; | |||||
| } | |||||
| .select2-container--default .select2-selection--single { | |||||
| border : 1px solid rgba(34,36,38,.15) !important; | |||||
| } | |||||
| .select2-container--default .select2-selection--single .select2-selection__rendered{ | |||||
| line-height: 38px !important; | |||||
| } | |||||
| </style> | </style> | ||||
| <div id="mask"> | <div id="mask"> | ||||
| @@ -129,6 +119,24 @@ | |||||
| {{.i18n.Tr "repo.cloudbrain.new"}} | {{.i18n.Tr "repo.cloudbrain.new"}} | ||||
| </h3> | </h3> | ||||
| <div class="ui attached segment"> | <div class="ui attached segment"> | ||||
| <div class="inline required field"> | |||||
| <label>计算资源</label> | |||||
| <div class="ui blue small menu compact selectcloudbrain"> | |||||
| <a class="active item" href="{{.RepoLink}}/cloudbrain/create"> | |||||
| <svg class="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16"> | |||||
| <path fill="none" d="M0 0h24v24H0z"/> | |||||
| <path d="M3 2.992C3 2.444 3.445 2 3.993 2h16.014a1 1 0 0 1 .993.992v18.016a.993.993 0 0 1-.993.992H3.993A1 1 0 0 1 3 21.008V2.992zM19 11V4H5v7h14zm0 2H5v7h14v-7zM9 6h6v2H9V6zm0 9h6v2H9v-2z"/> | |||||
| </svg> | |||||
| CPU/GPU | |||||
| </a> | |||||
| <a class="item" href="{{.RepoLink}}/modelarts/notebook/create"> | |||||
| <svg class="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16"> | |||||
| <path fill="none" d="M0 0h24v24H0z"/> | |||||
| <path d="M3 2.992C3 2.444 3.445 2 3.993 2h16.014a1 1 0 0 1 .993.992v18.016a.993.993 0 0 1-.993.992H3.993A1 1 0 0 1 3 21.008V2.992zM19 11V4H5v7h14zm0 2H5v7h14v-7zM9 6h6v2H9V6zm0 9h6v2H9v-2z"/> | |||||
| </svg> | |||||
| Ascend NPU</a> | |||||
| </div> | |||||
| </div> | |||||
| <div class="inline required field"> | <div class="inline required field"> | ||||
| <label>任务名称</label> | <label>任务名称</label> | ||||
| <input name="job_name" id="cloudbrain_job_name" placeholder="任务名称" value="{{.job_name}}" tabindex="3" autofocus required maxlength="254"> | <input name="job_name" id="cloudbrain_job_name" placeholder="任务名称" value="{{.job_name}}" tabindex="3" autofocus required maxlength="254"> | ||||
| @@ -240,7 +248,7 @@ | |||||
| <button class="ui green button" > | <button class="ui green button" > | ||||
| {{.i18n.Tr "repo.cloudbrain.new"}} | {{.i18n.Tr "repo.cloudbrain.new"}} | ||||
| </button> | </button> | ||||
| <a class="ui button" href="/">{{.i18n.Tr "repo.cloudbrain.cancel"}}</a> | |||||
| <a class="ui button cancel" href="">{{.i18n.Tr "repo.cloudbrain.cancel"}}</a> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </form> | </form> | ||||
| @@ -250,12 +258,7 @@ | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| {{template "base/footer" .}} | {{template "base/footer" .}} | ||||
| <link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" /> | |||||
| <script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script> | |||||
| <script> | <script> | ||||
| let url_href = window.location.pathname.split('create')[0] | |||||
| $(".ui.button").attr('href',url_href) | |||||
| let form = document.getElementById('form_id'); | let form = document.getElementById('form_id'); | ||||
| @@ -273,10 +276,6 @@ | |||||
| $('#messageInfo p').text(str) | $('#messageInfo p').text(str) | ||||
| return false | return false | ||||
| } | } | ||||
| // if(!value_image || !value_data){ | |||||
| // console.log("------------------------") | |||||
| // return false | |||||
| // } | |||||
| let min_value_task = value_task.toLowerCase() | let min_value_task = value_task.toLowerCase() | ||||
| $("input[name='job_name']").attr("value",min_value_task) | $("input[name='job_name']").attr("value",min_value_task) | ||||
| document.getElementById("mask").style.display = "block" | document.getElementById("mask").style.display = "block" | ||||
| @@ -7,11 +7,11 @@ | |||||
| <h4 class="ui header" id="vertical-segment"> | <h4 class="ui header" id="vertical-segment"> | ||||
| <div class="ui breadcrumb"> | <div class="ui breadcrumb"> | ||||
| <a class="section" href="{{.RepoLink}}/cloudbrain"> | |||||
| <a class="section" href="{{.RepoLink}}/debugjob?debugListType=all"> | |||||
| {{.i18n.Tr "repo.cloudbrain"}} | {{.i18n.Tr "repo.cloudbrain"}} | ||||
| </a> | </a> | ||||
| <div class="divider"> / </div> | <div class="divider"> / </div> | ||||
| <a class="section" href="{{.RepoLink}}/cloudbrain"> | |||||
| <a class="section backTodeBug" href="{{.RepoLink}}/debugjob?debugListType=CPU/GPU"> | |||||
| {{$.i18n.Tr "repo.modelarts.notebook"}} | {{$.i18n.Tr "repo.modelarts.notebook"}} | ||||
| </a> | </a> | ||||
| <div class="divider"> / </div> | <div class="divider"> / </div> | ||||
| @@ -98,3 +98,4 @@ | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| {{template "base/footer" .}} | {{template "base/footer" .}} | ||||
| @@ -5,10 +5,7 @@ | |||||
| .label_after::after{ | .label_after::after{ | ||||
| margin: -.2em 0 0 .2em; | margin: -.2em 0 0 .2em; | ||||
| content: '\00a0'; | content: '\00a0'; | ||||
| } | } | ||||
| .selectcloudbrain .active.item{ | .selectcloudbrain .active.item{ | ||||
| color: #0087f5 !important; | color: #0087f5 !important; | ||||
| border: 1px solid #0087f5; | border: 1px solid #0087f5; | ||||
| @@ -205,7 +202,6 @@ | |||||
| <div class="rect5"></div> | <div class="rect5"></div> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <!-- 提示框 --> | <!-- 提示框 --> | ||||
| <div class="alert"></div> | <div class="alert"></div> | ||||
| @@ -213,164 +209,132 @@ | |||||
| {{template "repo/header" .}} | {{template "repo/header" .}} | ||||
| <!-- 列表容器 --> | <!-- 列表容器 --> | ||||
| <div class="ui container"> | <div class="ui container"> | ||||
| <!-- 中间云脑和新建任务按钮 --> | |||||
| <!-- <div class="ui three column stack able grid"> | |||||
| <div class="column"> | |||||
| <h2>{{.i18n.Tr "repo.cloudbrain1"}}</h2> | |||||
| </div> | |||||
| <div class="column"> | |||||
| </div> | |||||
| <div class="column right aligned"> | |||||
| {{if .Permission.CanWrite $.UnitTypeCloudBrain}} | |||||
| <a class="ui green button" href="{{.RepoLink}}/cloudbrain/create">{{.i18n.Tr "repo.cloudbrain.new"}}</a> {{end}} | |||||
| </div> | |||||
| </div> | |||||
| <p>使用鹏城云脑计算资源进行调试,云脑1提供CPU / GPU资源,云脑2提供Ascend NPU资源;调试使用的数据集也需要上传到对应的环境。</p> | |||||
| <div class="ui blue mini menu selectcloudbrain"> | |||||
| <a class="active item" href="{{.RepoLink}}/cloudbrain">{{svg "octicon-server" 16}} CPU / GPU</a> | |||||
| <a class="item" href="{{.RepoLink}}/modelarts">{{svg "octicon-server" 16}} Ascend NPU</a> | |||||
| </div> --> | |||||
| <div class="ui two column stackable grid "> | <div class="ui two column stackable grid "> | ||||
| <div class="column"> | <div class="column"> | ||||
| <div class="ui blue small menu compact selectcloudbrain"> | <div class="ui blue small menu compact selectcloudbrain"> | ||||
| <a class="active item" href="{{.RepoLink}}/cloudbrain">{{$.i18n.Tr "repo.modelarts.notebook"}}</a> | |||||
| <a class="active item" href="{{.RepoLink}}/debugjob?debugListType=all">{{$.i18n.Tr "repo.modelarts.notebook"}}</a> | |||||
| <a class="item" href="{{.RepoLink}}/modelarts/train-job">{{$.i18n.Tr "repo.modelarts.train_job"}}</a> | <a class="item" href="{{.RepoLink}}/modelarts/train-job">{{$.i18n.Tr "repo.modelarts.train_job"}}</a> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div class="column right aligned"> | <div class="column right aligned"> | ||||
| <div class="ui selection dropdown" style="min-width: 10em;min-height:2.6em;border-radius: .28571429rem;margin-right: 1em;padding: .67em 3.2em .7em 1em;"> | <div class="ui selection dropdown" style="min-width: 10em;min-height:2.6em;border-radius: .28571429rem;margin-right: 1em;padding: .67em 3.2em .7em 1em;"> | ||||
| {{svg "octicon-server" 16}} | {{svg "octicon-server" 16}} | ||||
| <div class="default text" style="color: rgba(0,0,0,.87);"> CPU / GPU</div> | |||||
| <div class="default text" style="color: rgba(0,0,0,.87);"></div> | |||||
| <i class="dropdown icon"></i> | <i class="dropdown icon"></i> | ||||
| <div class="menu"> | <div class="menu"> | ||||
| <a class="item" href="{{.RepoLink}}/cloudbrain" data-value="11">CPU / GPU</a> | |||||
| <a class="item" href="{{.RepoLink}}/modelarts/notebook" data-value="22">Ascend NPU</a> | |||||
| <div class="item" data-value="all">全部</div> | |||||
| <div class="item" data-value="CPU/GPU">CPU/GPU</div> | |||||
| <div class="item" data-value="NPU">NPU</div> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| {{if .Permission.CanWrite $.UnitTypeCloudBrain}} | {{if .Permission.CanWrite $.UnitTypeCloudBrain}} | ||||
| <a class="ui green button" href="{{.RepoLink}}/cloudbrain/create">{{$.i18n.Tr "repo.modelarts.train_job.new_debug"}}</a>{{end}} | |||||
| <a class="ui green button" href="{{.RepoLink}}/cloudbrain/create">{{$.i18n.Tr "repo.modelarts.train_job.new_debug"}}</a> | |||||
| {{else}} | |||||
| <a class="ui disabled button">{{$.i18n.Tr "repo.modelarts.train_job.new_debug"}}</a> | |||||
| {{end}} | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| {{if eq 0 (len .Tasks)}} | |||||
| <div class="ui placeholder segment bgtask-none"> | |||||
| <div class="ui icon header bgtask-header-pic"></div> | |||||
| <div class="bgtask-content-header">未创建过调试任务</div> | |||||
| <div class="bgtask-content"> | |||||
| {{if $.RepoIsEmpty}} | |||||
| <div class="bgtask-content-txt">代码版本:您还没有初始化代码仓库,请先<a href="{{.RepoLink}}">创建代码版本</a>;</div> | |||||
| {{end}} | |||||
| <div class="bgtask-content-txt">运行时长:最长不超过4个小时,超过4个小时将自动停止;</div> | |||||
| <div class="bgtask-content-txt">数据集:云脑1提供 CPU / GPU 资源,云脑2提供 Ascend NPU 资源,调试使用的数据集也需要上传到对应的环境;</div> | |||||
| <div class="bgtask-content-txt">使用说明:可以参考启智AI协作平台<a href="https://git.openi.org.cn/zeizei/OpenI_Learning">小白训练营课程。</a></div> | |||||
| </div> | |||||
| </div> | |||||
| {{else}} | |||||
| <!-- 中下列表展示区 --> | <!-- 中下列表展示区 --> | ||||
| <div class="ui grid"> | <div class="ui grid"> | ||||
| <div class="row"> | <div class="row"> | ||||
| <div class="ui sixteen wide column"> | <div class="ui sixteen wide column"> | ||||
| <!-- 排序区 --> | |||||
| <!-- <div class="ui sixteen wide column"> | |||||
| <div class="ui two column stackable grid"> | |||||
| <div class="column"> | |||||
| </div> | |||||
| <div class="column right aligned"> | |||||
| <div class="ui right dropdown type jump item"> | |||||
| <span class="text"> | |||||
| {{.i18n.Tr "repo.issues.filter_sort"}}<i class="dropdown icon"></i> | |||||
| </span> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> --> | |||||
| <!-- 任务展示 --> | <!-- 任务展示 --> | ||||
| <!-- 表头 --> | <!-- 表头 --> | ||||
| <div class="dataset list"> | <div class="dataset list"> | ||||
| <div class="ui grid stackable" style="background: #f0f0f0;;"> | <div class="ui grid stackable" style="background: #f0f0f0;;"> | ||||
| <div class="row"> | <div class="row"> | ||||
| <div class="five wide column"> | |||||
| <div class="four wide column"> | |||||
| <span style="margin:0 6px">{{$.i18n.Tr "repo.cloudbrain_task"}}</span> | <span style="margin:0 6px">{{$.i18n.Tr "repo.cloudbrain_task"}}</span> | ||||
| </div> | </div> | ||||
| <div class="three wide column"> | |||||
| <span>{{$.i18n.Tr "repo.cloudbrain_status_createtime"}}</span> | |||||
| <div class="two wide column text center"> | |||||
| <span style="margin:0 6px">{{$.i18n.Tr "repo.modelarts.status"}}</span> | |||||
| </div> | |||||
| <div class="two wide column text center"> | |||||
| <span>{{$.i18n.Tr "repo.modelarts.createtime"}}</span> | |||||
| </div> | |||||
| <div class="two wide column text center"> | |||||
| <span>{{$.i18n.Tr "repo.modelarts.computing_resources"}}</span> | |||||
| </div> | </div> | ||||
| <div class="one wide column"> | |||||
| <div class="one wide column text center"> | |||||
| <span>{{$.i18n.Tr "repo.cloudbrain_creator"}}</span> | <span>{{$.i18n.Tr "repo.cloudbrain_creator"}}</span> | ||||
| </div> | </div> | ||||
| <div class="seven wide column text center"> | |||||
| <div class="five wide column text center"> | |||||
| <span>{{$.i18n.Tr "repo.cloudbrain_operate"}}</span> | <span>{{$.i18n.Tr "repo.cloudbrain_operate"}}</span> | ||||
| </div> | </div> | ||||
| </div> | |||||
| </div> | |||||
| </div> | </div> | ||||
| {{range .Tasks}} | {{range .Tasks}} | ||||
| <div class="ui grid stackable item"> | <div class="ui grid stackable item"> | ||||
| <div class="row"> | <div class="row"> | ||||
| <!-- 任务名 --> | <!-- 任务名 --> | ||||
| <div class="five wide column"> | |||||
| <a class="title" href="{{$.Link}}/{{.JobID}}" title="{{.JobName}}" style="font-size: 14px;"> | |||||
| <div class="four wide column"> | |||||
| <a class="title" href='{{if eq .ComputeResource "CPU/GPU"}}{{$.RepoLink}}/cloudbrain{{else}}{{$.RepoLink}}/modelarts/notebook{{end}}/{{.JobID}}' title="{{.JobName}}" style="font-size: 14px;"> | |||||
| <span class="fitted text_over" style="width: 90%;vertical-align: middle;">{{.JobName}}</span> | <span class="fitted text_over" style="width: 90%;vertical-align: middle;">{{.JobName}}</span> | ||||
| </a> | </a> | ||||
| </div> | </div> | ||||
| <div class="three wide column"> | |||||
| <!--任务状态 --> | |||||
| <span class="job-status" id="{{.JobID}}" data-repopath="{{$.RepoRelPath}}" data-jobid="{{.JobID}}"> | |||||
| <!-- {{.Status}} --> | |||||
| <!-- {{if eq .Status "RUNNING"}} | |||||
| <span style="display:flex;position: relative; justify-content: flex-start;"><i class="i-round i-bg-stop"></i><span style="margin-left: 0.4em;font-size: 12px;">运行中</span></span> | |||||
| <span style="display:flex;position: relative; justify-content: flex-start;"><i class="i-round i-bg-stop"></i><span style="margin-left: 0.4em;font-size: 12px;">运行中</span></span> | |||||
| {{else}} | |||||
| {{.Status}} | |||||
| {{end}} --> | |||||
| <div class="two wide column text center"> | |||||
| <!--任务状态 --> | |||||
| <span class="job-status" id="{{.JobID}}" data-repopath="{{$.RepoRelPath}}" data-jobid="{{.JobID}}" data-resource="{{.ComputeResource}}"> | |||||
| <span><i id="{{.JobID}}-icon" style="vertical-align: middle;" class="{{.Status}}"></i><span id="{{.JobID}}-text" style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span> | <span><i id="{{.JobID}}-icon" style="vertical-align: middle;" class="{{.Status}}"></i><span id="{{.JobID}}-text" style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span> | ||||
| </span> | </span> | ||||
| <!-- <span class="job-status" id="{{.JobID}}" data-repopath="{{$.RepoRelPath}}" data-jobid="{{.JobID}}" > | |||||
| {{if eq .Status "STOPPED"}} | |||||
| <span style="display:flex;position: relative; justify-content: flex-start;"><i class="i-round i-bg-stop"></i><span style="margin-left: 0.4em;font-size: 12px;">已停止</span></span> | |||||
| {{else if eq .Status "RUNNING"}} | |||||
| <span style="display:flex;position: relative; justify-content: flex-start;"><i class="i-round i-bg-running"></i><span style="margin-left: 0.4em;font-size: 12px;">运行中</span></span> | |||||
| {{else if eq .Status "FAILED"}} | |||||
| <span style="display:flex;position: relative; justify-content: flex-start;"><i class="i-round i-bg-running"></i><span style="margin-left: 0.4em;font-size: 12px;">运行失败</span></span> | |||||
| {{else if eq .Status "WAITING"}} | |||||
| <span style="display:flex;position: relative; justify-content: flex-start;"><i class="showCircle"></i><span style="margin-left: 0.4em;font-size: 12px;">初始化等待</span></span> | |||||
| {{end}} | |||||
| </span> --> | |||||
| </div> | |||||
| <div class="two wide column text center"> | |||||
| <!-- 任务创建时间 --> | <!-- 任务创建时间 --> | ||||
| <span style="font-size: 12px;margin-left: 0.4rem;" class="">{{TimeSinceUnix .Cloudbrain.CreatedUnix $.Lang}}</span> | <span style="font-size: 12px;margin-left: 0.4rem;" class="">{{TimeSinceUnix .Cloudbrain.CreatedUnix $.Lang}}</span> | ||||
| </div> | </div> | ||||
| <div class="one wide column"> | |||||
| <div class="two wide column text center"> | |||||
| <!-- 任务计算资源 --> | |||||
| <span style="font-size: 12px;margin-left: 0.4rem;" class="">{{.ComputeResource}}</span> | |||||
| </div> | |||||
| <div class="one wide column text center"> | |||||
| {{if .User.Name}} | {{if .User.Name}} | ||||
| <a href="{{AppSubUrl}}/{{.User.Name}}" title="{{.User.Name}}"><img class="ui avatar image" src="{{.User.RelAvatarLink}}"></a> | <a href="{{AppSubUrl}}/{{.User.Name}}" title="{{.User.Name}}"><img class="ui avatar image" src="{{.User.RelAvatarLink}}"></a> | ||||
| {{else}} | {{else}} | ||||
| <a title="Ghost"><img class="ui avatar image" src="{{AppSubUrl}}/user/avatar/Ghost/-1"></a> | <a title="Ghost"><img class="ui avatar image" src="{{AppSubUrl}}/user/avatar/Ghost/-1"></a> | ||||
| {{end}} | {{end}} | ||||
| </div> | </div> | ||||
| <div class="seven wide column text right"> | |||||
| <div class="five wide column text center"> | |||||
| <div class="ui compact buttons"> | <div class="ui compact buttons"> | ||||
| {{if and (ne .Status "WAITING") (ne .JobType "DEBUG")}} | |||||
| <!-- {{if and (ne .Status "WAITING") (ne .JobType "DEBUG")}} | |||||
| <a class="ui basic button" href="{{$.Link}}/{{.JobID}}/rate" target="_blank"> | <a class="ui basic button" href="{{$.Link}}/{{.JobID}}/rate" target="_blank"> | ||||
| 评分 | 评分 | ||||
| </a> | </a> | ||||
| {{end}} | |||||
| {{end}} --> | |||||
| <!-- 调试 --> | <!-- 调试 --> | ||||
| {{if $.Permission.CanWrite $.UnitTypeCloudBrain}} | |||||
| <a id="model-debug-{{.JobID}}" class="ui basic {{if not .CanDebug}}disabled {{else}}blue {{end}}button" href="{{$.Link}}/{{.JobID}}/debug" target="_blank"> | |||||
| {{$.i18n.Tr "repo.debug"}} | |||||
| </a> | |||||
| {{if .CanDebug}} | |||||
| {{if eq .ComputeResource "CPU/GPU"}} | |||||
| <a id="model-debug-{{.JobID}}" class='ui basic {{if ne .Status "RUNNING"}} disabled {{else}}blue {{end}}button' href="{{$.RepoLink}}/cloudbrain/{{.JobID}}/debug" target="_blank"> | |||||
| {{$.i18n.Tr "repo.debug"}} | |||||
| </a> | |||||
| {{else}} | |||||
| <a id="model-debug-{{.JobID}}" class='ui basic {{if ne .Status "RUNNING"}} disabled {{else}}blue {{end}}button' href="{{$.RepoLink}}/modelarts/notebook/{{.JobID}}/debug" target="_blank"> | |||||
| {{$.i18n.Tr "repo.debug"}} | |||||
| </a> | |||||
| {{end}} | |||||
| {{else}} | {{else}} | ||||
| <a class="ui basic disabled button" href="{{$.Link}}/{{.JobID}}/debug" target="_blank"> | |||||
| <a class="ui basic disabled button"> | |||||
| {{$.i18n.Tr "repo.debug"}} | {{$.i18n.Tr "repo.debug"}} | ||||
| </a> | </a> | ||||
| {{end}} | {{end}} | ||||
| <form id="stopForm-{{.JobID}}" action="{{$.Link}}/{{.JobID}}/stop" method="post" style="margin-left:-1px;"> | |||||
| <!-- 停止 --> | |||||
| <form id="stopForm-{{.JobID}}" action="{{if eq .ComputeResource "CPU/GPU"}}{{$.RepoLink}}/cloudbrain{{else}}{{$.RepoLink}}/modelarts/notebook{{end}}/{{.JobID}}/stop" method="post" style="margin-left:-1px;"> | |||||
| {{$.CsrfTokenHtml}} | {{$.CsrfTokenHtml}} | ||||
| {{if $.Permission.CanWrite $.UnitTypeCloudBrain}} | |||||
| <a id="stop-model-debug-{{.JobID}}" class="ui basic {{if or (eq .Status "STOPPED") (eq .Status "FAILED")}}disabled {{else}}blue {{end}}button" onclick="document.getElementById('stopForm-{{.JobID}}').submit();"> | |||||
| {{if .CanDel}} | |||||
| <a id="stop-model-debug-{{.JobID}}" class='ui basic {{if eq .Status "STOPPED" "FAILED" "START_FAILED" "STOPPING" "CREATING" "STARTING"}}disabled {{else}}blue {{end}}button' onclick="document.getElementById('stopForm-{{.JobID}}').submit();"> | |||||
| {{$.i18n.Tr "repo.stop"}} | {{$.i18n.Tr "repo.stop"}} | ||||
| </a> | </a> | ||||
| {{else}} | {{else}} | ||||
| @@ -378,45 +342,59 @@ | |||||
| {{$.i18n.Tr "repo.stop"}} | {{$.i18n.Tr "repo.stop"}} | ||||
| </a> | </a> | ||||
| {{end}} | {{end}} | ||||
| <input type="hidden" name="debugListType" value="all"> | |||||
| </form> | |||||
| <!-- 删除 --> | |||||
| <form id="delForm-{{.JobID}}" action="{{if eq .ComputeResource "CPU/GPU"}}{{$.RepoLink}}/cloudbrain{{else}}{{$.RepoLink}}/modelarts/notebook{{end}}/{{.JobID}}/del" method="post"> | |||||
| <input type="hidden" name="debugListType" value="all"> | |||||
| {{$.CsrfTokenHtml}} | |||||
| {{if .CanDel}} | |||||
| <a id="model-delete-{{.JobID}}" class='ui basic {{if eq .Status "STOPPED" "FAILED" "START_FAILED"}}blue {{else}}disabled {{end}}button' onclick="assertDelete(this)" style="border-radius: .28571429rem;"> | |||||
| {{$.i18n.Tr "repo.delete"}} | |||||
| </a> | |||||
| {{else}} | |||||
| <a class="ui basic button disabled" onclick="assertDelete(this)" style="border-radius: .28571429rem;"> | |||||
| {{$.i18n.Tr "repo.delete"}} | |||||
| </a> | |||||
| {{end}} | |||||
| </form> | </form> | ||||
| </div> | </div> | ||||
| <div class="ui compact buttons"> | |||||
| <!-- 模型下载 --> | |||||
| <a class="ui basic blue button" href="{{$.Link}}/{{.JobID}}/models" target="_blank"> | |||||
| {{$.i18n.Tr "repo.download"}} | |||||
| </a> | |||||
| <!-- 接收结果 --> | |||||
| <iframe src="" frameborder="0" name="iframeContent" style="display: none;"></iframe> | |||||
| {{if $.Permission.CanWrite $.UnitTypeCloudBrain}} | |||||
| <a id="model-image-{{.JobID}}" class="imageBtn ui basic {{if not .CanDebug}}disabled {{else}}blue {{end}}button" value="{{.CanDebug}}">{{$.i18n.Tr "repo.submit_image"}}</a> | |||||
| {{else}} | |||||
| <a class="imageBtn ui basic disabled button" value="{{.CanDebug}}">{{$.i18n.Tr "repo.submit_image"}}</a> | |||||
| {{end}} | |||||
| </div> | |||||
| <!-- 删除任务 --> | <!-- 删除任务 --> | ||||
| <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 basic button {{if not .CanDel}}disabled {{else}} blue {{end}}" onclick="assertDelete(this)" style="border-radius: .28571429rem;"> | |||||
| {{$.i18n.Tr "repo.delete"}} | |||||
| </a> | |||||
| {{else}} | |||||
| <a class="ui basic blue button disabled" onclick="assertDelete(this)" style="border-radius: .28571429rem;"> | |||||
| {{$.i18n.Tr "repo.delete"}} | |||||
| </a> | |||||
| {{end}} | |||||
| </form> | |||||
| <div class="ui compact buttons" style="{{if eq .ComputeResource "CPU/GPU"}} visibility: visible {{else}} visibility: hidden{{end}}"> | |||||
| <div class="ui dropdown" id="model_more" style="padding: .58928571em 1.125em .58928571em;"> | |||||
| <div class="text">更多</div> | |||||
| <i class="dropdown icon"></i> | |||||
| <div class="menu" style="right: auto;"> | |||||
| <div class="item" style="padding: 0 !important;"> | |||||
| <!-- 接收结果 --> | |||||
| <iframe src="" frameborder="0" name="iframeContent" style="display: none;"></iframe> | |||||
| {{if .CanDel}} | |||||
| <a id="model-image-{{.JobID}}" class='imageBtn ui basic {{if ne .Status "RUNNING"}}disabled {{else}}blue {{end}}button'>{{$.i18n.Tr "repo.submit_image"}}</a> | |||||
| {{else}} | |||||
| <a class="imageBtn ui basic disabled button">{{$.i18n.Tr "repo.submit_image"}}</a> | |||||
| {{end}} | |||||
| </div> | |||||
| <div class="item" style="padding: 0 !important;"> | |||||
| <!-- 模型下载 --> | |||||
| {{if .CanDel}} | |||||
| <a class="ui basic blue button" href="{{$.RepoLink}}/cloudbrain/{{.JobID}}/models" target="_blank">{{$.i18n.Tr "repo.download"}}</a> | |||||
| {{else}} | |||||
| <a class="ui basic disabled button">{{$.i18n.Tr "repo.download"}}</a> | |||||
| {{end}} | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | </div> | ||||
| <!-- 镜像列表弹窗 --> | <!-- 镜像列表弹窗 --> | ||||
| <div id="imageModal" class="modal" style="display: none;"> | <div id="imageModal" class="modal" style="display: none;"> | ||||
| <div class="modal-content"> | <div class="modal-content"> | ||||
| <!-- 表格 --> | <!-- 表格 --> | ||||
| <div class="ui form"> | <div class="ui form"> | ||||
| <form id="commitImageForm" action="{{$.Link}}/{{.JobID}}/commit_image" method="post" target="iframeContent"> | |||||
| <form id="commitImageForm" action="{{$.RepoLink}}/cloudbrain/{{.JobID}}/commit_image" method="post" target="iframeContent"> | |||||
| {{$.CsrfTokenHtml}} | {{$.CsrfTokenHtml}} | ||||
| <div class="row"> | <div class="row"> | ||||
| <p style="display: inline;">提交任务镜像</p> | <p style="display: inline;">提交任务镜像</p> | ||||
| @@ -433,10 +411,8 @@ | |||||
| <div class="inline field"> | <div class="inline field"> | ||||
| <label class="label_after">镜像描述:</label> | <label class="label_after">镜像描述:</label> | ||||
| <textarea name="description" maxlength="254" rows="8" style="width:75%;margin-left: 0.2em;"></textarea> | <textarea name="description" maxlength="254" rows="8" style="width:75%;margin-left: 0.2em;"></textarea> | ||||
| </div> | |||||
| <div class="ui divider"></div> | |||||
| </div> | |||||
| <div class="ui divider"></div> | |||||
| <div class="inline field"> | <div class="inline field"> | ||||
| <label></label> | <label></label> | ||||
| <button class="ui green button" onclick="showmask()"> | <button class="ui green button" onclick="showmask()"> | ||||
| @@ -448,24 +424,17 @@ | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| {{end}} {{template "base/paginate" .}} | {{end}} {{template "base/paginate" .}} | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| {{end}} | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <!-- 确认模态框 --> | <!-- 确认模态框 --> | ||||
| @@ -494,6 +463,10 @@ | |||||
| <script> | <script> | ||||
| // 调试和评分新开窗口 | // 调试和评分新开窗口 | ||||
| let url={{.RepoLink}} | |||||
| let getParam=location.search.split('?debugListType=').pop() | |||||
| let dropdownValue = getParam==='all'||getParam==='' ? '全部' : getParam | |||||
| localStorage.setItem('all',location.href) | |||||
| function stop(obj) { | function stop(obj) { | ||||
| if (obj.style.color != "rgb(204, 204, 204)") { | if (obj.style.color != "rgb(204, 204, 204)") { | ||||
| obj.target = '_blank' | obj.target = '_blank' | ||||
| @@ -501,7 +474,6 @@ | |||||
| return | return | ||||
| } | } | ||||
| } | } | ||||
| // 删除时用户确认 | // 删除时用户确认 | ||||
| function assertDelete(obj) { | function assertDelete(obj) { | ||||
| if (obj.style.color == "rgb(204, 204, 204)") { | if (obj.style.color == "rgb(204, 204, 204)") { | ||||
| @@ -535,30 +507,24 @@ | |||||
| $(".job-status").each((index, job) => { | $(".job-status").each((index, job) => { | ||||
| const jobID = job.dataset.jobid; | const jobID = job.dataset.jobid; | ||||
| const repoPath = job.dataset.repopath; | const repoPath = job.dataset.repopath; | ||||
| if (job.textContent.trim() == 'STOPPED' || job.textContent.trim() == 'FAILED') { | |||||
| const computeResource = job.dataset.resource | |||||
| const initArray = ['STOPPED','FAILED','START_FAILED','CREATE_FAILED'] | |||||
| if (initArray.includes(job.textContent.trim())) { | |||||
| return | return | ||||
| } | } | ||||
| $.get(`/api/v1/repos/${repoPath}/cloudbrain/${jobID}`, (data) => { | |||||
| const diffResource = computeResource == "NPU" ? 'modelarts/notebook' : 'cloudbrain' | |||||
| $.get(`/api/v1/repos/${repoPath}/${diffResource}/${jobID}`, (data) => { | |||||
| const jobID = data.JobID | const jobID = data.JobID | ||||
| const status = data.JobStatus | const status = data.JobStatus | ||||
| if (status != job.textContent.trim()) { | if (status != job.textContent.trim()) { | ||||
| console.log("---------") | |||||
| $('#' + jobID+'-icon').removeClass().addClass(status) | $('#' + jobID+'-icon').removeClass().addClass(status) | ||||
| $('#' + jobID+ '-text').text(status) | $('#' + jobID+ '-text').text(status) | ||||
| //if (status == 'STOPPED') { | |||||
| // window.location.reload() | |||||
| //} | |||||
| } | } | ||||
| if(status==="RUNNING"){ | if(status==="RUNNING"){ | ||||
| $('#model-debug-'+jobID).removeClass('disabled') | $('#model-debug-'+jobID).removeClass('disabled') | ||||
| $('#model-debug-'+jobID).addClass('blue') | $('#model-debug-'+jobID).addClass('blue') | ||||
| $('#model-image-'+jobID).removeClass('disabled') | $('#model-image-'+jobID).removeClass('disabled') | ||||
| $('#model-image-'+jobID).addClass('blue') | $('#model-image-'+jobID).addClass('blue') | ||||
| } | } | ||||
| if(status!=="RUNNING"){ | if(status!=="RUNNING"){ | ||||
| $('#model-debug-'+jobID).removeClass('blue') | $('#model-debug-'+jobID).removeClass('blue') | ||||
| @@ -567,23 +533,40 @@ | |||||
| $('#model-image-'+jobID).addClass('disabled') | $('#model-image-'+jobID).addClass('disabled') | ||||
| } | } | ||||
| if(status!=="STOPPED" || status!=="FAILED"){ | |||||
| if(["RUNNING","WAITING"].includes(status)){ | |||||
| $('#stop-model-debug-'+jobID).removeClass('disabled') | $('#stop-model-debug-'+jobID).removeClass('disabled') | ||||
| $('#stop-model-debug-'+jobID).addClass('blue') | $('#stop-model-debug-'+jobID).addClass('blue') | ||||
| $('#model-delete-'+jobID).removeClass('red') | |||||
| $('#model-delete-'+jobID).addClass('disabled') | |||||
| } | } | ||||
| if(status=="STOPPED" || status=="FAILED"){ | |||||
| if(["CREATING","STOPPING","STARTING","STOPPED","FAILED","START_FAILED"].includes(status)){ | |||||
| $('#stop-model-debug-'+jobID).removeClass('blue') | $('#stop-model-debug-'+jobID).removeClass('blue') | ||||
| $('#stop-model-debug-'+jobID).addClass('disabled') | $('#stop-model-debug-'+jobID).addClass('disabled') | ||||
| $('#model-delete-'+jobID).removeClass('disabled') | |||||
| $('#model-delete-'+jobID).addClass('red') | |||||
| } | |||||
| if(status==="STOPPED" || status==="FAILED"|| status==="START_FAILED"){ | |||||
| $('#model-delete-'+jobID).removeClass('disabled') | |||||
| $('#model-delete-'+jobID).addClass('blue') | |||||
| }else{ | |||||
| $('#model-delete-'+jobID).removeClass('blue') | |||||
| $('#model-delete-'+jobID).addClass('disabled') | |||||
| } | } | ||||
| }).fail(function(err) { | }).fail(function(err) { | ||||
| console.log(err); | console.log(err); | ||||
| }); | }); | ||||
| }); | }); | ||||
| }; | }; | ||||
| $(document).ready(function(){ | |||||
| $('.default.text').text(dropdownValue) | |||||
| $('.ui.dropdown') | |||||
| .dropdown({ | |||||
| action: 'hide', | |||||
| }) | |||||
| $('.ui.selection.dropdown').dropdown({ | |||||
| onChange:function(value){ | |||||
| location.href = `${url}/debugjob?debugListType=${value}` | |||||
| } | |||||
| }) | |||||
| }) | |||||
| // 获取弹窗 | // 获取弹窗 | ||||
| var modal = document.getElementById('imageModal'); | var modal = document.getElementById('imageModal'); | ||||
| @@ -638,4 +621,5 @@ | |||||
| } | } | ||||
| }) | }) | ||||
| } | } | ||||
| </script> | </script> | ||||
| @@ -97,16 +97,21 @@ | |||||
| <span>{{svg "octicon-code" 16}} {{.i18n.Tr "repo.code"}} <i class="dropdown icon"></i></span> | <span>{{svg "octicon-code" 16}} {{.i18n.Tr "repo.code"}} <i class="dropdown icon"></i></span> | ||||
| </a> | </a> | ||||
| <div class="dropdown-content"> | <div class="dropdown-content"> | ||||
| {{if and (.Permission.CanRead $.UnitTypeReleases) (not .IsEmptyRepo) }} | |||||
| <a style="border: none;" class="{{if .PageIsReleaseList}}active{{end}} item" href="{{.RepoLink}}/releases"> | <a style="border: none;" class="{{if .PageIsReleaseList}}active{{end}} item" href="{{.RepoLink}}/releases"> | ||||
| {{svg "octicon-tag" 16}} {{.i18n.Tr "repo.releases"}} <span class="ui {{if not .NumReleases}}gray{{else}}blue{{end}} small label">{{.NumReleases}}</span> | {{svg "octicon-tag" 16}} {{.i18n.Tr "repo.releases"}} <span class="ui {{if not .NumReleases}}gray{{else}}blue{{end}} small label">{{.NumReleases}}</span> | ||||
| </a> | </a> | ||||
| {{end}} | |||||
| {{if or (.Permission.CanRead $.UnitTypeWiki) (.Permission.CanRead $.UnitTypeExternalWiki)}} | |||||
| <a style="border: none;" class="{{if .PageIsWiki}}active{{end}} item" href="{{.RepoLink}}/wiki" {{if (.Permission.CanRead $.UnitTypeExternalWiki)}} target="_blank" rel="noopener noreferrer" {{end}}> | <a style="border: none;" class="{{if .PageIsWiki}}active{{end}} item" href="{{.RepoLink}}/wiki" {{if (.Permission.CanRead $.UnitTypeExternalWiki)}} target="_blank" rel="noopener noreferrer" {{end}}> | ||||
| {{svg "octicon-book" 16}} {{.i18n.Tr "repo.wiki"}} | {{svg "octicon-book" 16}} {{.i18n.Tr "repo.wiki"}} | ||||
| </a> | </a> | ||||
| {{end}} | |||||
| {{if and (.Permission.CanReadAny $.UnitTypePullRequests $.UnitTypeIssues $.UnitTypeReleases) (not .IsEmptyRepo)}} | |||||
| <a style="border: none;" class="{{if .PageIsActivity}}active{{end}} item" href="{{.RepoLink}}/activity"> | <a style="border: none;" class="{{if .PageIsActivity}}active{{end}} item" href="{{.RepoLink}}/activity"> | ||||
| {{svg "octicon-pulse" 16}} {{.i18n.Tr "repo.activity"}} | {{svg "octicon-pulse" 16}} {{.i18n.Tr "repo.activity"}} | ||||
| </a> | </a> | ||||
| {{end}} | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| @@ -134,12 +139,23 @@ | |||||
| {{if .Permission.CanRead $.UnitTypeDatasets}} | {{if .Permission.CanRead $.UnitTypeDatasets}} | ||||
| <a class="{{if .PageIsDataset}}active{{end}} item" href="{{.RepoLink}}/datasets?type=0"> | <a class="{{if .PageIsDataset}}active{{end}} item" href="{{.RepoLink}}/datasets?type=0"> | ||||
| {{svg "octicon-inbox" 16}} {{.i18n.Tr "datasets"}} | |||||
| <svg class="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16"><path fill="none" d="M0 0h24v24H0z"/><path d="M20.083 15.2l1.202.721a.5.5 0 0 1 0 .858l-8.77 5.262a1 1 0 0 1-1.03 0l-8.77-5.262a.5.5 0 0 1 0-.858l1.202-.721L12 20.05l8.083-4.85zm0-4.7l1.202.721a.5.5 0 0 1 0 .858L12 17.65l-9.285-5.571a.5.5 0 0 1 0-.858l1.202-.721L12 15.35l8.083-4.85zm-7.569-9.191l8.771 5.262a.5.5 0 0 1 0 .858L12 13 2.715 7.429a.5.5 0 0 1 0-.858l8.77-5.262a1 1 0 0 1 1.03 0zM12 3.332L5.887 7 12 10.668 18.113 7 12 3.332z"/></svg> | |||||
| {{.i18n.Tr "datasets"}} | |||||
| </a> | |||||
| {{end}} | |||||
| {{if .Permission.CanRead $.UnitTypeModelManage}} | |||||
| <a class="{{if .isModelManage}}active{{end}} item" href="{{.RepoLink}}/modelmanage/show_model"> | |||||
| <svg class="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16"><path fill="none" d="M0 0h24v24H0z"/><path d="M3.741 1.408l18.462 10.154a.5.5 0 0 1 0 .876L3.741 22.592A.5.5 0 0 1 3 22.154V1.846a.5.5 0 0 1 .741-.438zM5 13v6.617L18.85 12 5 4.383V11h5v2H5z"/></svg> | |||||
| {{.i18n.Tr "repo.model_manager"}} | |||||
| </a> | </a> | ||||
| {{end}} | {{end}} | ||||
| {{if .Permission.CanRead $.UnitTypeCloudBrain}} | {{if .Permission.CanRead $.UnitTypeCloudBrain}} | ||||
| <a class="{{if .PageIsCloudBrain}}active{{end}} item" href="{{.RepoLink}}/cloudbrain"> | |||||
| <span>{{svg "octicon-server" 16}} {{.i18n.Tr "repo.cloudbrain"}}<i class="question circle icon link cloudbrain-question" data-content={{.i18n.Tr "repo.cloudbrain_helper"}} data-position="top center" data-variation="mini"></i></span> | |||||
| <a class="{{if .PageIsCloudBrain}}active{{end}} item" href="{{.RepoLink}}/debugjob?debugListType=all"> | |||||
| <span> | |||||
| <svg class="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16"><path fill="none" d="M0 0h24v24H0z"/><path d="M4 3h16a1 1 0 0 1 1 1v7H3V4a1 1 0 0 1 1-1zM3 13h18v7a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1v-7zm4 3v2h3v-2H7zM7 6v2h3V6H7z"/></svg> | |||||
| {{.i18n.Tr "repo.cloudbrain"}} | |||||
| <i class="question circle icon link cloudbrain-question" data-content={{.i18n.Tr "repo.cloudbrain_helper"}} data-position="top center" data-variation="mini"></i> | |||||
| </span> | |||||
| </a> | </a> | ||||
| {{end}} | {{end}} | ||||
| <!-- {{if .IsSigned}} | <!-- {{if .IsSigned}} | ||||
| @@ -164,86 +180,5 @@ | |||||
| <div class="ui tabs divider"></div> | <div class="ui tabs divider"></div> | ||||
| </div> | </div> | ||||
| <div class="ui select_cloudbrain modal"> | |||||
| <div class="header"> | |||||
| {{$.i18n.Tr "repo.cloudbrain_selection"}} | |||||
| </div> | |||||
| <div class="content"> | |||||
| <div class="ui form" method="post"> | |||||
| <div class="grouped fields"> | |||||
| <label for="CloudBrain">{{$.i18n.Tr "repo.cloudbrain_platform_selection"}}</label> | |||||
| <div class="field"> | |||||
| <div class="ui radio checkbox"> | |||||
| <input type="radio" name="CloudBrainSelect" checked tabindex="0" class="hidden" value="0"> | |||||
| <label>{{$.i18n.Tr "repo.cloudbrain1"}}</label> | |||||
| </div> | |||||
| </div> | |||||
| <div class="field"> | |||||
| <div class="ui radio checkbox"> | |||||
| <input type="radio" name="CloudBrainSelect" tabindex="0" class="hidden" value="1"> | |||||
| <label>{{$.i18n.Tr "repo.cloudbrain2"}}</label> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div class="actions"> | |||||
| <div class="mb-2 ui positive right labeled icon button"> | |||||
| {{$.i18n.Tr "repo.confirm_choice"}} | |||||
| <i class="checkmark icon"></i> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <script src="https://cdn.jsdelivr.net/npm/jquery@3.2.1/dist/jquery.min.js"></script> | <script src="https://cdn.jsdelivr.net/npm/jquery@3.2.1/dist/jquery.min.js"></script> | ||||
| <script> | |||||
| // 点击云脑进行选择云脑平台并进入相应的界面 | |||||
| $('.item.cloudbrain').click(function(){ | |||||
| $('.ui.select_cloudbrain.modal') | |||||
| .modal('closable', false) | |||||
| .modal('show'); | |||||
| // $('.ui.select_cloudbrain.modal').modal('show'); | |||||
| $('.ui.radio.checkbox').checkbox(); | |||||
| var repolink = $(".cloudbrain_link").text() | |||||
| console.log(repolink) | |||||
| $(".ui.positive.right.icon.button").click(function(){ | |||||
| // 声明一个变量来接收以及获取单选框选择的情况 | |||||
| var checked_radio = $("input[name='CloudBrainSelect']:checked").val() | |||||
| console.log(checked_radio) | |||||
| if(checked_radio=='0'){ | |||||
| window.location.href = repolink+'/cloudbrain' | |||||
| }else if(checked_radio=='1'){ | |||||
| window.location.href = repolink+'/modelarts/notebook' | |||||
| }else{ | |||||
| return; | |||||
| } | |||||
| }) | |||||
| }) | |||||
| // 点击数据集进行选择云脑平台并进入相应的界面 | |||||
| $('.item.dataset').click(function(){ | |||||
| $('.ui.select_cloudbrain.modal') | |||||
| .modal('closable', false) | |||||
| .modal('show'); | |||||
| $('.ui.radio.checkbox').checkbox(); | |||||
| var repolink = $(".dataset_link").text() | |||||
| console.log(repolink) | |||||
| $(".ui.positive.right.icon.button").click(function(){ | |||||
| // 声明一个变量来接收以及获取单选框选择的情况 | |||||
| var checked_radio = $("input[type='radio']:checked").val() | |||||
| $('.ui.select_cloudbrain.modal') | |||||
| .modal('show'); | |||||
| // 向后端传递对象 | |||||
| window.location.href = repolink + "/datasets?type=" + checked_radio | |||||
| }) | |||||
| }) | |||||
| $('.question.circle.icon').hover(function(){ | |||||
| $(this).popup('show') | |||||
| $('.ui.popup.mini.top.center').css({"border-color":'rgba(50, 145, 248, 100)',"color":"rgba(3, 102, 214, 100)","border-radius":"5px","border-shadow":"none"}) | |||||
| }); | |||||
| </script> | |||||
| @@ -1,551 +0,0 @@ | |||||
| <!-- 头部导航栏 --> | |||||
| {{template "base/head" .}} | |||||
| <style> | |||||
| .selectcloudbrain .active.item{ | |||||
| color: #0087f5 !important; | |||||
| border: 1px solid #0087f5; | |||||
| margin: -1px; | |||||
| background: #FFF !important; | |||||
| } | |||||
| #deletemodel { | |||||
| width: 100%; | |||||
| height: 100%; | |||||
| } | |||||
| /* 弹窗 */ | |||||
| #mask { | |||||
| position: fixed; | |||||
| top: 0px; | |||||
| left: 0px; | |||||
| right: 0px; | |||||
| bottom: 0px; | |||||
| filter: alpha(opacity=60); | |||||
| background-color: #777; | |||||
| z-index: 1000; | |||||
| display: none; | |||||
| opacity: 0.8; | |||||
| -moz-opacity: 0.5; | |||||
| padding-top: 100px; | |||||
| color: #000000 | |||||
| } | |||||
| #loadingPage { | |||||
| margin: 200px auto; | |||||
| width: 50px; | |||||
| height: 40px; | |||||
| text-align: center; | |||||
| font-size: 10px; | |||||
| display: block; | |||||
| } | |||||
| #loadingPage>div { | |||||
| background-color: green; | |||||
| height: 100%; | |||||
| width: 6px; | |||||
| display: inline-block; | |||||
| -webkit-animation: sk-stretchdelay 1.2s infinite ease-in-out; | |||||
| animation: sk-stretchdelay 1.2s infinite ease-in-out; | |||||
| } | |||||
| #loadingPage .rect2 { | |||||
| -webkit-animation-delay: -1.1s; | |||||
| animation-delay: -1.1s; | |||||
| } | |||||
| #loadingPage .rect3 { | |||||
| -webkit-animation-delay: -1.0s; | |||||
| animation-delay: -1.0s; | |||||
| } | |||||
| #loadingPage .rect4 { | |||||
| -webkit-animation-delay: -0.9s; | |||||
| animation-delay: -0.9s; | |||||
| } | |||||
| #loadingPage .rect5 { | |||||
| -webkit-animation-delay: -0.8s; | |||||
| animation-delay: -0.8s; | |||||
| } | |||||
| @-webkit-keyframes sk-stretchdelay { | |||||
| 0%, | |||||
| 40%, | |||||
| 100% { | |||||
| -webkit-transform: scaleY(0.4) | |||||
| } | |||||
| 20% { | |||||
| -webkit-transform: scaleY(1.0) | |||||
| } | |||||
| } | |||||
| @keyframes sk-stretchdelay { | |||||
| 0%, | |||||
| 40%, | |||||
| 100% { | |||||
| transform: scaleY(0.4); | |||||
| -webkit-transform: scaleY(0.4); | |||||
| } | |||||
| 20% { | |||||
| transform: scaleY(1.0); | |||||
| -webkit-transform: scaleY(1.0); | |||||
| } | |||||
| } | |||||
| /* 消息框 */ | |||||
| .alert { | |||||
| display: none; | |||||
| position: fixed; | |||||
| width: 100%; | |||||
| z-index: 1001; | |||||
| padding: 15px; | |||||
| border: 1px solid transparent; | |||||
| border-radius: 4px; | |||||
| text-align: center; | |||||
| font-weight: bold; | |||||
| } | |||||
| .alert-success { | |||||
| color: #3c763d; | |||||
| background-color: #dff0d8; | |||||
| border-color: #d6e9c6; | |||||
| } | |||||
| .alert-info { | |||||
| color: #31708f; | |||||
| background-color: #d9edf7; | |||||
| border-color: #bce8f1; | |||||
| } | |||||
| .alert-warning { | |||||
| color: #8a6d3b; | |||||
| background-color: #fcf8e3; | |||||
| border-color: #faebcc; | |||||
| } | |||||
| .alert-danger { | |||||
| color: #a94442; | |||||
| background-color: #f2dede; | |||||
| border-color: #ebccd1; | |||||
| } | |||||
| .pusher { | |||||
| width: calc(100% - 260px); | |||||
| box-sizing: border-box; | |||||
| } | |||||
| /* 弹窗 (background) */ | |||||
| #imageModal { | |||||
| display: none; | |||||
| position: fixed; | |||||
| z-index: 1; | |||||
| left: 0; | |||||
| top: 0; | |||||
| width: 100%; | |||||
| height: 100%; | |||||
| overflow: auto; | |||||
| background-color: rgb(0, 0, 0); | |||||
| background-color: rgba(0, 0, 0, 0.4); | |||||
| } | |||||
| /* 弹窗内容 */ | |||||
| .modal-content { | |||||
| background-color: #fefefe; | |||||
| margin: 15% auto; | |||||
| padding: 20px; | |||||
| border: 1px solid #888; | |||||
| width: 30%; | |||||
| } | |||||
| /* 关闭按钮 */ | |||||
| .close { | |||||
| color: #aaa; | |||||
| float: right; | |||||
| font-size: 28px; | |||||
| font-weight: bold; | |||||
| } | |||||
| .close:hover, | |||||
| .close:focus { | |||||
| color: black; | |||||
| text-decoration: none; | |||||
| cursor: pointer; | |||||
| } | |||||
| .dis { | |||||
| margin-bottom: 20px; | |||||
| } | |||||
| .disabled { | |||||
| cursor: pointer; | |||||
| pointer-events: none; | |||||
| } | |||||
| </style> | |||||
| <!-- 弹窗 --> | |||||
| <div id="mask"> | |||||
| <div id="loadingPage"> | |||||
| <div class="rect1"></div> | |||||
| <div class="rect2"></div> | |||||
| <div class="rect3"></div> | |||||
| <div class="rect4"></div> | |||||
| <div class="rect5"></div> | |||||
| </div> | |||||
| </div> | |||||
| <!-- 提示框 --> | |||||
| <div class="alert"></div> | |||||
| <div class="repository release dataset-list view"> | |||||
| {{template "repo/header" .}} | |||||
| <!-- 列表容器 --> | |||||
| <div class="ui container"> | |||||
| {{template "base/alert" .}} | |||||
| <!-- 中间云脑和新建任务按钮 --> | |||||
| <div class="ui two column stackable grid "> | |||||
| <div class="column"> | |||||
| <div class="ui blue small menu compact selectcloudbrain"> | |||||
| <a class="active item" href="{{.RepoLink}}/modelarts/notebook">{{$.i18n.Tr "repo.modelarts.notebook"}}</a> | |||||
| <a class="item" href="{{.RepoLink}}/modelarts/train-job">{{$.i18n.Tr "repo.modelarts.train_job"}}</a> | |||||
| </div> | |||||
| </div> | |||||
| <div class="column right aligned"> | |||||
| <div class="ui selection dropdown" style="min-width: 10em;min-height:2.6em;border-radius: .28571429rem;margin-right: 1em;padding: .67em 3.2em .7em 1em;"> | |||||
| {{svg "octicon-server" 16}} | |||||
| <div class="default text" style="color: rgba(0,0,0,.87);"> Ascend NPU</div> | |||||
| <i class="dropdown icon"></i> | |||||
| <div class="menu"> | |||||
| <a class="item" href="{{.RepoLink}}/cloudbrain" data-value="11">CPU / GPU</a> | |||||
| <a class="item" href="{{.RepoLink}}/modelarts/notebook" data-value="22">Ascend NPU</a> | |||||
| </div> | |||||
| </div> | |||||
| {{if .Permission.CanWrite $.UnitTypeCloudBrain}} | |||||
| <a class="ui green button" href="{{.RepoLink}}/modelarts/notebook/create">{{$.i18n.Tr "repo.modelarts.train_job.new_debug"}}</a>{{end}} | |||||
| </div> | |||||
| </div> | |||||
| <!-- 中下列表展示区 --> | |||||
| <div class="ui grid"> | |||||
| <div class="row"> | |||||
| <div class="ui sixteen wide column"> | |||||
| <!-- 排序区 --> | |||||
| <!-- <div class="ui sixteen wide column"> | |||||
| <div class="ui two column stackable grid"> | |||||
| <div class="column"> | |||||
| </div> | |||||
| <div class="column right aligned"> | |||||
| <div class="ui right dropdown type jump item"> | |||||
| <span class="text"> | |||||
| {{.i18n.Tr "repo.issues.filter_sort"}}<i class="dropdown icon"></i> | |||||
| </span> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> --> | |||||
| <!-- 任务展示 --> | |||||
| <div class="dataset list"> | |||||
| <!-- 表头 --> | |||||
| <div class="ui grid stackable" style="background: #f0f0f0;;"> | |||||
| <div class="row"> | |||||
| <div class="six wide column"> | |||||
| <span style="margin:0 6px">{{$.i18n.Tr "repo.cloudbrain_task"}}</span> | |||||
| </div> | |||||
| <div class="three wide column"> | |||||
| <span>{{$.i18n.Tr "repo.cloudbrain_status_createtime"}}</span> | |||||
| </div> | |||||
| <div class="two wide column text center"> | |||||
| <span>{{$.i18n.Tr "repo.cloudbrain_creator"}}</span> | |||||
| </div> | |||||
| <div class="five wide column text center"> | |||||
| <span style="margin-left: 5rem;">{{$.i18n.Tr "repo.cloudbrain_operate"}}</span> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| {{range .Tasks}} | |||||
| <div class="ui grid stackable item"> | |||||
| <div class="row"> | |||||
| <!-- 任务名 --> | |||||
| <div class="six wide column"> | |||||
| <a class="title" href="{{$.Link}}/{{.JobID}}" title="{{.JobName}}" style="font-size: 14px;"> | |||||
| <span class="fitted" style="width: 90%;vertical-align: middle;">{{.JobName}}</span> | |||||
| </a> | |||||
| </div> | |||||
| <div class="three wide column"> | |||||
| <!--任务状态 --> | |||||
| <!-- <span class="ui compact button job-status" id="{{.JobID}}" data-repopath="{{$.RepoRelPath}}" data-jobid="{{.JobID}}"> | |||||
| {{.Status}} | |||||
| </span> --> | |||||
| <span class="job-status" id="{{.JobID}}" data-repopath="{{$.RepoRelPath}}" data-jobid="{{.JobID}}"> | |||||
| <span><i id="{{.JobID}}-icon" style="vertical-align: middle;" class="{{.Status}}"></i><span id="{{.JobID}}-text" style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span> | |||||
| </span> | |||||
| <!-- 任务创建时间 --> | |||||
| <span style="font-size: 12px;margin-left: 0.4rem;" class="">{{TimeSinceUnix .Cloudbrain.CreatedUnix $.Lang}}</span> | |||||
| </div> | |||||
| <div class="two wide column text center"> | |||||
| {{if .User.Name}} | |||||
| <a href="{{AppSubUrl}}/{{.User.Name}}" title="{{.User.Name}}"><img class="ui avatar image" src="{{.User.RelAvatarLink}}"></a> | |||||
| {{else}} | |||||
| <a title="Ghost"><img class="ui avatar image" src="{{AppSubUrl}}/user/avatar/Ghost/-1"></a> | |||||
| {{end}} | |||||
| </div> | |||||
| <div class="five wide column text right"> | |||||
| <div class="ui compact buttons"> | |||||
| <!-- <a class="ui basic blue button" href="{{$.Link}}/{{.JobID}}"> | |||||
| 查看 | |||||
| </a> --> | |||||
| {{if $.Permission.CanWrite $.UnitTypeCloudBrain}} | |||||
| <a id="model-debug-{{.JobID}}" style="margin-right: 2rem;" class="ui basic {{if not .CanDebug}}disabled {{else}}blue {{end}}button" href="{{$.Link}}/{{.JobID}}/debug" target="_blank"> | |||||
| {{$.i18n.Tr "repo.debug"}} | |||||
| </a> | |||||
| {{else}} | |||||
| <a style="margin-right: 2rem;" class="ui basic disabled button" href="{{$.Link}}/{{.JobID}}/debug" target="_blank"> | |||||
| {{$.i18n.Tr "repo.debug"}} | |||||
| </a> | |||||
| {{end}} | |||||
| <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 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}} | |||||
| <a style="margin-right: 2rem;" class="ui basic disabled button" onclick="document.getElementById('stopForm-{{.JobID}}').submit();"> | |||||
| {{$.i18n.Tr "repo.stop"}} | |||||
| </a> | |||||
| {{end}} | |||||
| </form> | |||||
| </div> | |||||
| <!-- <div class="ui compact buttons" style="margin-right:10px;"> --> | |||||
| <!-- 模型下载 --> | |||||
| <!-- <a class="ui basic blue button" href="{{$.Link}}/{{.JobID}}/models" target="_blank"> | |||||
| 模型下载 | |||||
| </a> --> | |||||
| <!-- 接收结果 --> | |||||
| <!-- <iframe src="" frameborder="0" name="iframeContent" style="display: none;"></iframe> | |||||
| <a class="imageBtn ui basic {{if not .CanDebug}}disabled {{else}}blue {{end}}button" value="{{.CanDebug}}">提交镜像</a> --> | |||||
| <!-- </div> --> | |||||
| <!-- 删除任务 --> | |||||
| <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 basic button {{if eq .Status "RUNNING" "CREATING" "WAITING" "STARTING" "STOPPING" }}disabled {{else}} blue {{end}}" onclick="assertDelete(this)" style="border-radius: .28571429rem;"> | |||||
| {{$.i18n.Tr "repo.delete"}} | |||||
| </a> | |||||
| {{else}} | |||||
| <a class="ui basic blue button disabled" onclick="assertDelete(this)" style="border-radius: .28571429rem;"> | |||||
| {{$.i18n.Tr "repo.delete"}} | |||||
| </a> | |||||
| {{end}} | |||||
| </form> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| {{end}} {{template "base/paginate" .}} | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <!-- 确认模态框 --> | |||||
| <div id="deletemodel"> | |||||
| <div class="ui basic modal"> | |||||
| <div class="ui icon header"> | |||||
| <i class="trash icon"></i> 删除任务 | |||||
| </div> | |||||
| <div class="content"> | |||||
| <p>你确认删除该任务么?此任务一旦删除不可恢复。</p> | |||||
| </div> | |||||
| <div class="actions"> | |||||
| <div class="ui red basic inverted cancel button"> | |||||
| <i class="remove icon"></i> 取消操作 | |||||
| </div> | |||||
| <div class="ui green basic inverted ok button"> | |||||
| <i class="checkmark icon"></i> 确定操作 | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| {{template "base/footer" .}} | |||||
| <script> | |||||
| // 调试和评分新开窗口 | |||||
| function stop(obj) { | |||||
| if (obj.style.color != "rgb(204, 204, 204)") { | |||||
| obj.target = '_blank' | |||||
| } else { | |||||
| return | |||||
| } | |||||
| } | |||||
| // 删除时用户确认 | |||||
| function assertDelete(obj) { | |||||
| if (obj.style.color == "rgb(204, 204, 204)") { | |||||
| return | |||||
| } else { | |||||
| var delId = obj.parentNode.id | |||||
| flag = 1; | |||||
| $('.ui.basic.modal') | |||||
| .modal({ | |||||
| onDeny: function() { | |||||
| flag = false | |||||
| }, | |||||
| onApprove: function() { | |||||
| document.getElementById(delId).submit() | |||||
| flag = true | |||||
| }, | |||||
| onHidden: function() { | |||||
| if (flag == false) { | |||||
| $('.alert').html('您已取消操作').removeClass('alert-success').addClass('alert-danger').show().delay(1500).fadeOut(); | |||||
| } | |||||
| } | |||||
| }) | |||||
| .modal('show') | |||||
| } | |||||
| } | |||||
| // 加载任务状态 | |||||
| var timeid = window.setInterval(loadJobStatus, 15000); | |||||
| $(document).ready(loadJobStatus); | |||||
| function loadJobStatus() { | |||||
| $(".job-status").each((index, job) => { | |||||
| const jobID = job.dataset.jobid; | |||||
| const repoPath = job.dataset.repopath; | |||||
| if (job.textContent.trim() == 'STOPPED' || job.textContent.trim() == 'START_FAILED' || job.textContent.trim() == 'CREATE_FAILED') { | |||||
| return | |||||
| } | |||||
| $.get(`/api/v1/repos/${repoPath}/modelarts/notebook/${jobID}`, (data) => { | |||||
| const jobID = data.JobID | |||||
| const status = data.JobStatus | |||||
| if (status != job.textContent.trim()) { | |||||
| $('#' + jobID+'-icon').removeClass().addClass(status) | |||||
| $('#' + jobID+ '-text').text(status) | |||||
| //if (status == 'STOPPED') { | |||||
| // window.location.reload() | |||||
| //} | |||||
| } | |||||
| if(status==="RUNNING"){ | |||||
| $('#model-debug-'+jobID).removeClass('disabled') | |||||
| $('#model-debug-'+jobID).addClass('blue') | |||||
| } | |||||
| if(status!=="RUNNING"){ | |||||
| $('#model-debug-'+jobID).removeClass('blue') | |||||
| $('#model-debug-'+jobID).addClass('disabled') | |||||
| } | |||||
| 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') | |||||
| } | |||||
| if(status=="STOPPED" || status=="FAILED" ){ | |||||
| $('#stop-model-debug-'+jobID).removeClass('blue') | |||||
| $('#stop-model-debug-'+jobID).addClass('disabled') | |||||
| $('#model-delete-'+jobID).removeClass('disabled') | |||||
| $('#model-delete-'+jobID).addClass('red') | |||||
| } | |||||
| 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); | |||||
| }); | |||||
| }); | |||||
| }; | |||||
| // 获取弹窗 | |||||
| var modal = document.getElementById('imageModal'); | |||||
| // 打开弹窗的按钮对象 | |||||
| var btns = document.getElementsByClassName("imageBtn"); | |||||
| // 获取 <span> 元素,用于关闭弹窗 | |||||
| var spans = document.getElementsByClassName('close'); | |||||
| // 点击按钮打开弹窗 | |||||
| for (i = 0; i < btns.length; i++) { | |||||
| btns[i].onclick = function() { | |||||
| modal.style.display = "block"; | |||||
| } | |||||
| } | |||||
| // 点击 <span> (x), 关闭弹窗 | |||||
| for (i = 0; i < spans.length; i++) { | |||||
| spans[i].onclick = function() { | |||||
| modal.style.display = "none"; | |||||
| } | |||||
| } | |||||
| // 在用户点击其他地方时,关闭弹窗 | |||||
| window.onclick = function(event) { | |||||
| if (event.target == modal) { | |||||
| modal.style.display = "none"; | |||||
| } | |||||
| } | |||||
| // 显示弹窗,弹出相应的信息 | |||||
| function showmask() { | |||||
| $('#imageModal').css('display', 'none') | |||||
| $('#mask').css('display', 'block') | |||||
| $("iframe[name=iframeContent]").on("load", function() { | |||||
| var responseText = $("iframe")[0].contentDocument.body.getElementsByTagName("pre")[0].innerHTML; | |||||
| var json1 = JSON.parse(responseText) | |||||
| $('#mask').css('display', 'none') | |||||
| parent.location.href | |||||
| if (json1.result_code === "0") { | |||||
| $('.alert').html('操作成功!').removeClass('alert-danger').addClass('alert-success').show().delay(1500).fadeOut(); | |||||
| } else { | |||||
| $('.alert').html(json1.error_msg).removeClass('alert-success').addClass('alert-danger').show().delay(5000).fadeOut(); | |||||
| } | |||||
| }) | |||||
| } | |||||
| </script> | |||||
| @@ -1,89 +1,8 @@ | |||||
| {{template "base/head" .}} | {{template "base/head" .}} | ||||
| <style> | <style> | ||||
| /* 遮罩层css效果图 */ | |||||
| #mask { | |||||
| position: fixed; | |||||
| top: 0px; | |||||
| left: 0px; | |||||
| right: 0px; | |||||
| bottom: 0px; | |||||
| filter: alpha(opacity=60); | |||||
| background-color: #777; | |||||
| z-index: 1000; | |||||
| .inline.required.field.cloudbrain_benchmark { | |||||
| display: none; | display: none; | ||||
| opacity: 0.8; | |||||
| -moz-opacity: 0.5; | |||||
| padding-top: 100px; | |||||
| color: #000000 | |||||
| } | |||||
| /* 加载圈css效果图 */ | |||||
| #loadingPage { | |||||
| margin: 200px auto; | |||||
| width: 50px; | |||||
| height: 40px; | |||||
| text-align: center; | |||||
| font-size: 10px; | |||||
| display: block; | |||||
| } | |||||
| #loadingPage>div { | |||||
| background-color: green; | |||||
| height: 100%; | |||||
| width: 6px; | |||||
| display: inline-block; | |||||
| -webkit-animation: sk-stretchdelay 1.2s infinite ease-in-out; | |||||
| animation: sk-stretchdelay 1.2s infinite ease-in-out; | |||||
| } | |||||
| #loadingPage .rect2 { | |||||
| -webkit-animation-delay: -1.1s; | |||||
| animation-delay: -1.1s; | |||||
| } | |||||
| #loadingPage .rect3 { | |||||
| -webkit-animation-delay: -1.0s; | |||||
| animation-delay: -1.0s; | |||||
| } | |||||
| #loadingPage .rect4 { | |||||
| -webkit-animation-delay: -0.9s; | |||||
| animation-delay: -0.9s; | |||||
| } | |||||
| #loadingPage .rect5 { | |||||
| -webkit-animation-delay: -0.8s; | |||||
| animation-delay: -0.8s; | |||||
| } | |||||
| @-webkit-keyframes sk-stretchdelay { | |||||
| 0%, | |||||
| 40%, | |||||
| 100% { | |||||
| -webkit-transform: scaleY(0.4) | |||||
| } | |||||
| 20% { | |||||
| -webkit-transform: scaleY(1.0) | |||||
| } | |||||
| } | |||||
| @keyframes sk-stretchdelay { | |||||
| 0%, | |||||
| 40%, | |||||
| 100% { | |||||
| transform: scaleY(0.4); | |||||
| -webkit-transform: scaleY(0.4); | |||||
| } | |||||
| 20% { | |||||
| transform: scaleY(1.0); | |||||
| -webkit-transform: scaleY(1.0); | |||||
| } | |||||
| } | |||||
| .inline.required.field.cloudbrain_benchmark { | |||||
| display: none; | |||||
| } | |||||
| } | |||||
| </style> | </style> | ||||
| <div id="mask"> | <div id="mask"> | ||||
| @@ -110,6 +29,23 @@ | |||||
| </h3> | </h3> | ||||
| <div class="ui attached segment"> | <div class="ui attached segment"> | ||||
| <!-- <br> --> | <!-- <br> --> | ||||
| <div class="inline required field"> | |||||
| <label>计算资源</label> | |||||
| <div class="ui blue small menu compact selectcloudbrain"> | |||||
| <a class="item" href="{{.RepoLink}}/cloudbrain/create"> | |||||
| <svg class="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16"> | |||||
| <path fill="none" d="M0 0h24v24H0z"/> | |||||
| <path d="M3 2.992C3 2.444 3.445 2 3.993 2h16.014a1 1 0 0 1 .993.992v18.016a.993.993 0 0 1-.993.992H3.993A1 1 0 0 1 3 21.008V2.992zM19 11V4H5v7h14zm0 2H5v7h14v-7zM9 6h6v2H9V6zm0 9h6v2H9v-2z"/> | |||||
| </svg> | |||||
| CPU/GPU</a> | |||||
| <a class="active item" href="{{.RepoLink}}/modelarts/notebook/create"> | |||||
| <svg class="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16"> | |||||
| <path fill="none" d="M0 0h24v24H0z"/> | |||||
| <path d="M3 2.992C3 2.444 3.445 2 3.993 2h16.014a1 1 0 0 1 .993.992v18.016a.993.993 0 0 1-.993.992H3.993A1 1 0 0 1 3 21.008V2.992zM19 11V4H5v7h14zm0 2H5v7h14v-7zM9 6h6v2H9V6zm0 9h6v2H9v-2z"/> | |||||
| </svg> | |||||
| Ascend NPU</a> | |||||
| </div> | |||||
| </div> | |||||
| <div class="inline required field"> | <div class="inline required field"> | ||||
| <label>任务名称</label> | <label>任务名称</label> | ||||
| <input name="job_name" id="cloudbrain_job_name" placeholder="任务名称" value="{{.job_name}}" tabindex="3" autofocus required maxlength="254"> | <input name="job_name" id="cloudbrain_job_name" placeholder="任务名称" value="{{.job_name}}" tabindex="3" autofocus required maxlength="254"> | ||||
| @@ -156,7 +92,7 @@ | |||||
| <button class="ui green button"> | <button class="ui green button"> | ||||
| {{.i18n.Tr "repo.cloudbrain.new"}} | {{.i18n.Tr "repo.cloudbrain.new"}} | ||||
| </button> | </button> | ||||
| <a class="ui button" href="/">{{.i18n.Tr "repo.cloudbrain.cancel"}}</a> | |||||
| <a class="ui button cancel" href="">{{.i18n.Tr "repo.cloudbrain.cancel"}}</a> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </form> | </form> | ||||
| @@ -166,10 +102,6 @@ | |||||
| {{template "base/footer" .}} | {{template "base/footer" .}} | ||||
| <script> | <script> | ||||
| // 取消创建跳转 | |||||
| let url_href = window.location.pathname.split('create')[0] | |||||
| $(".ui.button").attr('href',url_href) | |||||
| // 判断必填选项是否填写正确 | // 判断必填选项是否填写正确 | ||||
| let form = document.getElementById('form_id'); | let form = document.getElementById('form_id'); | ||||
| @@ -7,11 +7,11 @@ | |||||
| <h4 class="ui header" id="vertical-segment"> | <h4 class="ui header" id="vertical-segment"> | ||||
| <div class="ui breadcrumb"> | <div class="ui breadcrumb"> | ||||
| <a class="section" href="{{.RepoLink}}/cloudbrain"> | |||||
| <a class="section" href="{{.RepoLink}}/debugjob?debugListType=all"> | |||||
| {{.i18n.Tr "repo.cloudbrain"}} | {{.i18n.Tr "repo.cloudbrain"}} | ||||
| </a> | </a> | ||||
| <div class="divider"> / </div> | <div class="divider"> / </div> | ||||
| <a class="section" href="{{.RepoLink}}/modelarts/notebook"> | |||||
| <a class="section backTodeBug" href="{{.RepoLink}}/debugjob?debugListType=NPU"> | |||||
| {{$.i18n.Tr "repo.modelarts.notebook"}} | {{$.i18n.Tr "repo.modelarts.notebook"}} | ||||
| </a> | </a> | ||||
| <div class="divider"> / </div> | <div class="divider"> / </div> | ||||
| @@ -2,184 +2,6 @@ | |||||
| {{template "base/head" .}} | {{template "base/head" .}} | ||||
| <style> | <style> | ||||
| .selectcloudbrain .active.item{ | |||||
| color: #0087f5 !important; | |||||
| border: 1px solid #0087f5; | |||||
| margin: -1px; | |||||
| background: #FFF !important; | |||||
| } | |||||
| #deletemodel { | |||||
| width: 100%; | |||||
| height: 100%; | |||||
| } | |||||
| /* 弹窗 */ | |||||
| #mask { | |||||
| position: fixed; | |||||
| top: 0px; | |||||
| left: 0px; | |||||
| right: 0px; | |||||
| bottom: 0px; | |||||
| filter: alpha(opacity=60); | |||||
| background-color: #777; | |||||
| z-index: 1000; | |||||
| display: none; | |||||
| opacity: 0.8; | |||||
| -moz-opacity: 0.5; | |||||
| padding-top: 100px; | |||||
| color: #000000 | |||||
| } | |||||
| #loadingPage { | |||||
| margin: 200px auto; | |||||
| width: 50px; | |||||
| height: 40px; | |||||
| text-align: center; | |||||
| font-size: 10px; | |||||
| display: block; | |||||
| } | |||||
| #loadingPage>div { | |||||
| background-color: green; | |||||
| height: 100%; | |||||
| width: 6px; | |||||
| display: inline-block; | |||||
| -webkit-animation: sk-stretchdelay 1.2s infinite ease-in-out; | |||||
| animation: sk-stretchdelay 1.2s infinite ease-in-out; | |||||
| } | |||||
| #loadingPage .rect2 { | |||||
| -webkit-animation-delay: -1.1s; | |||||
| animation-delay: -1.1s; | |||||
| } | |||||
| #loadingPage .rect3 { | |||||
| -webkit-animation-delay: -1.0s; | |||||
| animation-delay: -1.0s; | |||||
| } | |||||
| #loadingPage .rect4 { | |||||
| -webkit-animation-delay: -0.9s; | |||||
| animation-delay: -0.9s; | |||||
| } | |||||
| #loadingPage .rect5 { | |||||
| -webkit-animation-delay: -0.8s; | |||||
| animation-delay: -0.8s; | |||||
| } | |||||
| @-webkit-keyframes sk-stretchdelay { | |||||
| 0%, | |||||
| 40%, | |||||
| 100% { | |||||
| -webkit-transform: scaleY(0.4) | |||||
| } | |||||
| 20% { | |||||
| -webkit-transform: scaleY(1.0) | |||||
| } | |||||
| } | |||||
| @keyframes sk-stretchdelay { | |||||
| 0%, | |||||
| 40%, | |||||
| 100% { | |||||
| transform: scaleY(0.4); | |||||
| -webkit-transform: scaleY(0.4); | |||||
| } | |||||
| 20% { | |||||
| transform: scaleY(1.0); | |||||
| -webkit-transform: scaleY(1.0); | |||||
| } | |||||
| } | |||||
| /* 消息框 */ | |||||
| .alert { | |||||
| display: none; | |||||
| position: fixed; | |||||
| width: 100%; | |||||
| z-index: 1001; | |||||
| padding: 15px; | |||||
| border: 1px solid transparent; | |||||
| border-radius: 4px; | |||||
| text-align: center; | |||||
| font-weight: bold; | |||||
| } | |||||
| .alert-success { | |||||
| color: #3c763d; | |||||
| background-color: #dff0d8; | |||||
| border-color: #d6e9c6; | |||||
| } | |||||
| .alert-info { | |||||
| color: #31708f; | |||||
| background-color: #d9edf7; | |||||
| border-color: #bce8f1; | |||||
| } | |||||
| .alert-warning { | |||||
| color: #8a6d3b; | |||||
| background-color: #fcf8e3; | |||||
| border-color: #faebcc; | |||||
| } | |||||
| .alert-danger { | |||||
| color: #a94442; | |||||
| background-color: #f2dede; | |||||
| border-color: #ebccd1; | |||||
| } | |||||
| .pusher { | |||||
| width: calc(100% - 260px); | |||||
| box-sizing: border-box; | |||||
| } | |||||
| /* 弹窗 (background) */ | |||||
| #imageModal { | |||||
| display: none; | |||||
| position: fixed; | |||||
| z-index: 1; | |||||
| left: 0; | |||||
| top: 0; | |||||
| width: 100%; | |||||
| height: 100%; | |||||
| overflow: auto; | |||||
| background-color: rgb(0, 0, 0); | |||||
| background-color: rgba(0, 0, 0, 0.4); | |||||
| } | |||||
| /* 弹窗内容 */ | |||||
| .modal-content { | |||||
| background-color: #fefefe; | |||||
| margin: 15% auto; | |||||
| padding: 20px; | |||||
| border: 1px solid #888; | |||||
| width: 30%; | |||||
| } | |||||
| /* 关闭按钮 */ | |||||
| .close { | |||||
| color: #aaa; | |||||
| float: right; | |||||
| font-size: 28px; | |||||
| font-weight: bold; | |||||
| } | |||||
| .close:hover, | |||||
| .close:focus { | |||||
| color: black; | |||||
| text-decoration: none; | |||||
| cursor: pointer; | |||||
| } | |||||
| .dis { | |||||
| margin-bottom: 20px; | |||||
| } | |||||
| .disabled { | |||||
| cursor: pointer; | |||||
| pointer-events: none; | |||||
| } | |||||
| .fontsize14{ | .fontsize14{ | ||||
| font-size: 14px; | font-size: 14px; | ||||
| } | } | ||||
| @@ -207,77 +29,38 @@ | |||||
| <!-- 列表容器 --> | <!-- 列表容器 --> | ||||
| <div class="ui container"> | <div class="ui container"> | ||||
| {{template "base/alert" .}} | {{template "base/alert" .}} | ||||
| <!-- 中间云脑和新建任务按钮 --> | |||||
| <!-- <div class="ui three column stack able grid"> | |||||
| <div class="column"> | |||||
| <h2>{{.i18n.Tr "repo.cloudbrain2"}}</h2> | |||||
| </div> | |||||
| <div class="column"> | |||||
| </div> | |||||
| <div class="column right aligned"> | |||||
| {{if .Permission.CanWrite $.UnitTypeCloudBrain}} | |||||
| <a class="ui green button" href="{{.RepoLink}}/modelarts/create">{{.i18n.Tr "repo.cloudbrain.new"}}</a> {{end}} | |||||
| </div> | |||||
| <div class="column right aligned"> | |||||
| {{if .Permission.CanWrite $.UnitTypeCloudBrain}} | |||||
| <a class="ui blue button" href="{{.RepoLink}}/modelarts/train-job/create">{{.i18n.Tr "repo.cloudbrain.new"}}</a> {{end}} | |||||
| </div> | |||||
| </div> | |||||
| <p>使用鹏城云脑计算资源进行调试,云脑1提供CPU / GPU资源,云脑2提供Ascend NPU资源;调试使用的数据集也需要上传到对应的环境。</p> | |||||
| <div class="ui blue mini menu selectcloudbrain"> | |||||
| <a class="item" href="{{.RepoLink}}/cloudbrain">{{svg "octicon-server" 16}} CPU / GPU</a> | |||||
| <a class="active item" href="{{.RepoLink}}/modelarts">{{svg "octicon-server" 16}} Ascend NPU</a> | |||||
| </div> --> | |||||
| <div class="ui two column stackable grid "> | <div class="ui two column stackable grid "> | ||||
| <div class="column"> | <div class="column"> | ||||
| <div class="ui blue small menu compact selectcloudbrain"> | <div class="ui blue small menu compact selectcloudbrain"> | ||||
| <a class="item" href="{{.RepoLink}}/cloudbrain">{{$.i18n.Tr "repo.modelarts.notebook"}}</a> | |||||
| <a class="item" href="{{.RepoLink}}/debugjob?debugListType=all">{{$.i18n.Tr "repo.modelarts.notebook"}}</a> | |||||
| <a class="active item" href="{{.RepoLink}}/modelarts/train-job">{{$.i18n.Tr "repo.modelarts.train_job"}}</a> | <a class="active item" href="{{.RepoLink}}/modelarts/train-job">{{$.i18n.Tr "repo.modelarts.train_job"}}</a> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div class="column right aligned"> | <div class="column right aligned"> | ||||
| <!-- <div class="ui selection dropdown" style="min-width: 10em;min-height:2.6em;border-radius: .28571429rem;margin-right: 1em;padding: .67em 3.2em .7em 1em;"> | |||||
| {{svg "octicon-server" 16}} | |||||
| <div class="default text" style="color: rgba(0,0,0,.87);"> Ascend NPU</div> | |||||
| <i class="dropdown icon"></i> | |||||
| <div class="menu"> | |||||
| <a class="item" href="{{.RepoLink}}/cloudbrain" data-value="11">CPU / GPU</a> | |||||
| <a class="item" href="{{.RepoLink}}/modelarts/notebook" data-value="22">Ascend NPU</a> | |||||
| </div> | |||||
| </div> --> | |||||
| {{if .Permission.CanWrite $.UnitTypeCloudBrain}} | {{if .Permission.CanWrite $.UnitTypeCloudBrain}} | ||||
| <a class="ui green button" href="{{.RepoLink}}/modelarts/train-job/create">{{$.i18n.Tr "repo.modelarts.train_job.new_train"}}</a>{{end}} | |||||
| <a class="ui green button" href="{{.RepoLink}}/modelarts/train-job/create">{{$.i18n.Tr "repo.modelarts.train_job.new_train"}}</a> | |||||
| {{else}} | |||||
| <a class="ui disabled button" >{{$.i18n.Tr "repo.modelarts.train_job.new_train"}}</a> | |||||
| {{end}} | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| {{if eq 0 (len .Tasks)}} | |||||
| <div class="ui placeholder segment bgtask-none"> | |||||
| <div class="ui icon header bgtask-header-pic"></div> | |||||
| <div class="bgtask-content-header">未创建过训练任务</div> | |||||
| <div class="bgtask-content"> | |||||
| {{if $.RepoIsEmpty}} | |||||
| <div class="bgtask-content-txt">代码版本:您还没有初始化代码仓库,请先<a href="{{.RepoLink}}">创建代码版本;</a></div> | |||||
| {{end}} | |||||
| <div class="bgtask-content-txt">数据集:云脑1提供 CPU / GPU 资源,云脑2提供 Ascend NPU 资源,调试使用的数据集也需要上传到对应的环境;</div> | |||||
| <div class="bgtask-content-txt">使用说明:可以参考启智AI协作平台<a href="https://git.openi.org.cn/zeizei/OpenI_Learning">小白训练营课程。</a></div> | |||||
| </div> | |||||
| </div> | |||||
| {{else}} | |||||
| <!-- 中下列表展示区 --> | <!-- 中下列表展示区 --> | ||||
| <div class="ui grid"> | <div class="ui grid"> | ||||
| <div class="row"> | <div class="row"> | ||||
| <div class="ui sixteen wide column"> | <div class="ui sixteen wide column"> | ||||
| <!-- 排序区 --> | |||||
| <!-- <div class="ui sixteen wide column"> | |||||
| <div class="ui two column stackable grid"> | |||||
| <div class="column"> | |||||
| </div> | |||||
| <div class="column right aligned"> | |||||
| <div class="ui right dropdown type jump item"> | |||||
| <span class="text"> | |||||
| {{.i18n.Tr "repo.issues.filter_sort"}}<i class="dropdown icon"></i> | |||||
| </span> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> --> | |||||
| <!-- 任务展示 --> | <!-- 任务展示 --> | ||||
| <div class="dataset list"> | <div class="dataset list"> | ||||
| @@ -308,13 +91,9 @@ | |||||
| <div class="three wide column text center padding0"> | <div class="three wide column text center padding0"> | ||||
| <span>{{$.i18n.Tr "repo.cloudbrain_operate"}}</span> | <span>{{$.i18n.Tr "repo.cloudbrain_operate"}}</span> | ||||
| </div> | </div> | ||||
| </div> | |||||
| </div> | |||||
| </div> | </div> | ||||
| {{range .Tasks}} | {{range .Tasks}} | ||||
| <div class="ui grid stackable item"> | <div class="ui grid stackable item"> | ||||
| <div class="row"> | <div class="row"> | ||||
| @@ -340,14 +119,6 @@ | |||||
| <div class="two wide column text center padding0"> | <div class="two wide column text center padding0"> | ||||
| <span style="font-size: 12px;" class="">{{TimeSinceUnix .Cloudbrain.CreatedUnix $.Lang}}</span> | <span style="font-size: 12px;" class="">{{TimeSinceUnix .Cloudbrain.CreatedUnix $.Lang}}</span> | ||||
| </div> | </div> | ||||
| <!-- <div class="two wide column"> | |||||
| <span class="job-status" id="{{.JobID}}" data-repopath="{{$.RepoRelPath}}" data-jobid="{{.JobID}}"> | |||||
| <span><i id="{{.JobID}}-icon" style="vertical-align: middle;" class="{{.Status}}"></i><span id="{{.JobID}}-text" style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span> | |||||
| </span> | |||||
| <span style="font-size: 12px;margin-left: 0.4rem;" class="">{{TimeSinceUnix .Cloudbrain.CreatedUnix $.Lang}}</span> | |||||
| </div> --> | |||||
| <!-- 任务运行时间 --> | <!-- 任务运行时间 --> | ||||
| <div class="two wide column text center padding0"> | <div class="two wide column text center padding0"> | ||||
| <span style="font-size: 12px;" id="duration-{{.JobID}}"></span> | <span style="font-size: 12px;" id="duration-{{.JobID}}"></span> | ||||
| @@ -366,31 +137,10 @@ | |||||
| </div> | </div> | ||||
| <div class="three wide column text center padding0"> | <div class="three wide column text center padding0"> | ||||
| <!-- <div class="ui compact buttons"> | |||||
| <form id="stopForm-{{.JobID}}" action="/api/v1/repos{{$.Link}}/{{.JobID}}/stop_version" method="post"> | |||||
| <input type="hidden" name="version_name" value="{{.VersionName}}"> | |||||
| {{$.CsrfTokenHtml}} | |||||
| {{if $.Permission.CanWrite $.UnitTypeCloudBrain}} | |||||
| <a style="padding: 0.5rem 1rem;" id="stop-model-debug-{{.JobID}}" class="ui basic {{if eq .Status "KILLED" "FAILED" "START_FAILED" "KILLING" "COMPLETED"}}disabled {{else}}blue {{end}}button" onclick="document.getElementById('stopForm-{{.JobID}}').submit();"> | |||||
| {{$.i18n.Tr "repo.stop"}} | |||||
| </a> | |||||
| {{else}} | |||||
| <a style="padding: 0.5rem 1rem;" class="ui basic disabled button" onclick="document.getElementById('stopForm-{{.JobID}}').submit();"> | |||||
| {{$.i18n.Tr "repo.stop"}} | |||||
| </a> | |||||
| {{end}} | |||||
| </form> | |||||
| </div> --> | |||||
| <!-- 模型下载 --> | |||||
| <!-- <div class="ui compact buttons"> | |||||
| <a style="padding: 0.5rem;" class="ui basic blue button" href="{{$.Link}}/{{.JobID}}/models" target="_blank"> | |||||
| {{$.i18n.Tr "repo.model_download"}} | |||||
| </a> | |||||
| </div> --> | |||||
| <!-- 删除任务 --> | |||||
| <!-- 停止任务 --> | |||||
| <div class="ui compact buttons"> | <div class="ui compact buttons"> | ||||
| {{$.CsrfTokenHtml}} | {{$.CsrfTokenHtml}} | ||||
| {{if $.Permission.CanWrite $.UnitTypeCloudBrain}} | |||||
| {{if .CanDel}} | |||||
| <a style="padding: 0.5rem 1rem;" id="{{.VersionName}}-stop" class="ui basic {{if eq .Status "KILLED" "FAILED" "START_FAILED" "KILLING" "COMPLETED"}}disabled {{else}} blue {{end}}button" onclick="stopVersion({{.VersionName}},{{.JobID}})"> | <a style="padding: 0.5rem 1rem;" id="{{.VersionName}}-stop" class="ui basic {{if eq .Status "KILLED" "FAILED" "START_FAILED" "KILLING" "COMPLETED"}}disabled {{else}} blue {{end}}button" onclick="stopVersion({{.VersionName}},{{.JobID}})"> | ||||
| {{$.i18n.Tr "repo.stop"}} | {{$.i18n.Tr "repo.stop"}} | ||||
| </a> | </a> | ||||
| @@ -401,15 +151,16 @@ | |||||
| {{end}} | {{end}} | ||||
| </div> | </div> | ||||
| <!-- 删除任务 --> | |||||
| <form class="ui compact buttons" id="delForm-{{.JobID}}" action="{{$.Link}}/{{.JobID}}/del" method="post"> | <form class="ui compact buttons" id="delForm-{{.JobID}}" action="{{$.Link}}/{{.JobID}}/del" method="post"> | ||||
| {{$.CsrfTokenHtml}} | {{$.CsrfTokenHtml}} | ||||
| {{if $.Permission.CanWrite $.UnitTypeCloudBrain}} | |||||
| {{if .CanDel}} | |||||
| <a style="padding: 0.5rem 1rem;margin-left:0.2rem" id="model-delete-{{.JobID}}" class="ui basic blue button" onclick="assertDelete(this)" style="border-radius: .28571429rem;"> | <a style="padding: 0.5rem 1rem;margin-left:0.2rem" id="model-delete-{{.JobID}}" class="ui basic blue button" onclick="assertDelete(this)" style="border-radius: .28571429rem;"> | ||||
| {{$.i18n.Tr "repo.delete"}} | {{$.i18n.Tr "repo.delete"}} | ||||
| </a> | </a> | ||||
| {{else}} | {{else}} | ||||
| <a style="padding: 0.5rem 1rem;margin-left:0.2rem" class="ui basic button disabled" onclick="assertDelete(this)" style="border-radius: .28571429rem;"> | |||||
| {{$.i18n.Tr "repo.delete"}} | |||||
| <a style="padding: 0.5rem 1rem;margin-left:0.2rem" class="ui basic button disabled" style="border-radius: .28571429rem;"> | |||||
| {{$.i18n.Tr "repo.delete"}} | |||||
| </a> | </a> | ||||
| {{end}} | {{end}} | ||||
| </form> | </form> | ||||
| @@ -422,6 +173,7 @@ | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| {{end}} | |||||
| </div> | </div> | ||||
| @@ -455,7 +207,6 @@ | |||||
| {{template "base/footer" .}} | {{template "base/footer" .}} | ||||
| <script> | <script> | ||||
| console.log({{.Tasks}}) | console.log({{.Tasks}}) | ||||
| // 调试和评分新开窗口 | // 调试和评分新开窗口 | ||||
| function stop(obj) { | function stop(obj) { | ||||
| @@ -47,87 +47,7 @@ | |||||
| border-radius: 5px 0px 0px 5px; | border-radius: 5px 0px 0px 5px; | ||||
| line-height: 21px; | line-height: 21px; | ||||
| text-align: center; | text-align: center; | ||||
| color: #C2C7CC;" | |||||
| } | |||||
| #mask { | |||||
| position: fixed; | |||||
| top: 0px; | |||||
| left: 0px; | |||||
| right: 0px; | |||||
| bottom: 0px; | |||||
| filter: alpha(opacity=60); | |||||
| background-color: #777; | |||||
| z-index: 1000; | |||||
| display: none; | |||||
| opacity: 0.8; | |||||
| -moz-opacity: 0.5; | |||||
| padding-top: 100px; | |||||
| color: #000000 | |||||
| } | |||||
| /* 加载圈css效果图 */ | |||||
| #loadingPage { | |||||
| margin: 200px auto; | |||||
| width: 50px; | |||||
| height: 40px; | |||||
| text-align: center; | |||||
| font-size: 10px; | |||||
| display: block; | |||||
| } | |||||
| #loadingPage>div { | |||||
| background-color: green; | |||||
| height: 100%; | |||||
| width: 6px; | |||||
| display: inline-block; | |||||
| -webkit-animation: sk-stretchdelay 1.2s infinite ease-in-out; | |||||
| animation: sk-stretchdelay 1.2s infinite ease-in-out; | |||||
| } | |||||
| #loadingPage .rect2 { | |||||
| -webkit-animation-delay: -1.1s; | |||||
| animation-delay: -1.1s; | |||||
| } | |||||
| #loadingPage .rect3 { | |||||
| -webkit-animation-delay: -1.0s; | |||||
| animation-delay: -1.0s; | |||||
| } | |||||
| #loadingPage .rect4 { | |||||
| -webkit-animation-delay: -0.9s; | |||||
| animation-delay: -0.9s; | |||||
| } | |||||
| #loadingPage .rect5 { | |||||
| -webkit-animation-delay: -0.8s; | |||||
| animation-delay: -0.8s; | |||||
| } | |||||
| .left2{ | |||||
| margin-left: -2px; | |||||
| } | |||||
| @-webkit-keyframes sk-stretchdelay { | |||||
| 0%, | |||||
| 40%, | |||||
| 100% { | |||||
| -webkit-transform: scaleY(0.4) | |||||
| } | |||||
| 20% { | |||||
| -webkit-transform: scaleY(1.0) | |||||
| } | |||||
| } | |||||
| @keyframes sk-stretchdelay { | |||||
| 0%, | |||||
| 40%, | |||||
| 100% { | |||||
| transform: scaleY(0.4); | |||||
| -webkit-transform: scaleY(0.4); | |||||
| } | |||||
| 20% { | |||||
| transform: scaleY(1.0); | |||||
| -webkit-transform: scaleY(1.0); | |||||
| } | |||||
| color: #C2C7CC; | |||||
| } | } | ||||
| </style> | </style> | ||||
| @@ -183,9 +103,9 @@ | |||||
| {{end}} | {{end}} | ||||
| {{end}} | {{end}} | ||||
| {{else}} | {{else}} | ||||
| <option name="branch_name" value="{{.BranchName}}">{{.BranchName}}</option> | |||||
| <option name="branch_name" value="{{.branchName}}">{{.branchName}}</option> | |||||
| {{range $k, $v :=.Branches}} | {{range $k, $v :=.Branches}} | ||||
| {{ if ne $v $.BranchName }} | |||||
| {{ if ne $v $.branchName }} | |||||
| <option name="branch_name" value="{{$v}}">{{$v}}</option> | <option name="branch_name" value="{{$v}}">{{$v}}</option> | ||||
| {{end}} | {{end}} | ||||
| {{end}} | {{end}} | ||||
| @@ -227,6 +147,7 @@ | |||||
| <span> | <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> | <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> | </span> | ||||
| <a href="https://git.openi.org.cn/OpenIOSSG/MINIST_Example" target="_blank">查看样例</a> | |||||
| </div> | </div> | ||||
| <div class="required unite min_title inline field"> | <div class="required unite min_title inline field"> | ||||
| <label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.dataset"}}</label> | <label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.dataset"}}</label> | ||||
| @@ -239,6 +160,7 @@ | |||||
| <option name="attachment" value="{{.UUID}}">{{.Attachment.Name}}</option> | <option name="attachment" value="{{.UUID}}">{{.Attachment.Name}}</option> | ||||
| {{end}} | {{end}} | ||||
| </select> | </select> | ||||
| <span class="tooltips">数据集位置存储在环境变量data_url中,训练输出路径存储在环境变量train_url中。</span> | |||||
| </div> | </div> | ||||
| <div class="inline unite min_title field"> | <div class="inline unite min_title field"> | ||||
| @@ -347,7 +269,6 @@ | |||||
| sever_num.val(parseInt(sever_num.val())+1) | sever_num.val(parseInt(sever_num.val())+1) | ||||
| } | } | ||||
| }) | }) | ||||
| // 参数增加、删除、修改、保存 | // 参数增加、删除、修改、保存 | ||||
| function Add_parameter(i){ | function Add_parameter(i){ | ||||
| value = '<div class="two fields width85" id= "para'+ i +'">' + | value = '<div class="two fields width85" id= "para'+ i +'">' + | ||||
| @@ -165,7 +165,6 @@ td, th { | |||||
| {{template "repo/header" .}} | {{template "repo/header" .}} | ||||
| <div class="ui container"> | <div class="ui container"> | ||||
| <h4 class="ui header" id="vertical-segment"> | <h4 class="ui header" id="vertical-segment"> | ||||
| <!-- <a href="javascript:window.history.back();"><i class="arrow left icon"></i>返回</a> --> | |||||
| <div class="ui breadcrumb"> | <div class="ui breadcrumb"> | ||||
| <a class="section" href="{{.RepoLink}}/cloudbrain"> | <a class="section" href="{{.RepoLink}}/cloudbrain"> | ||||
| {{.i18n.Tr "repo.cloudbrain"}} | {{.i18n.Tr "repo.cloudbrain"}} | ||||
| @@ -187,22 +186,21 @@ td, th { | |||||
| <span class="accordion-panel-title-content"> | <span class="accordion-panel-title-content"> | ||||
| <span> | <span> | ||||
| <div style="float: right;"> | <div style="float: right;"> | ||||
| <!-- <a class="ti-action-menu-item {{if ne .Status "COMPLETED"}}disabled {{end}}">创建模型</a> --> | |||||
| {{$.CsrfTokenHtml}} | {{$.CsrfTokenHtml}} | ||||
| {{if $.canNewJob}} | |||||
| {{if .CanModify}} | |||||
| <a class="ti-action-menu-item" href="{{$.RepoLink}}/modelarts/train-job/{{.JobID}}/create_version?version_name={{.VersionName}}">{{$.i18n.Tr "repo.modelarts.modify"}}</a> | <a class="ti-action-menu-item" href="{{$.RepoLink}}/modelarts/train-job/{{.JobID}}/create_version?version_name={{.VersionName}}">{{$.i18n.Tr "repo.modelarts.modify"}}</a> | ||||
| {{else}} | {{else}} | ||||
| <a class="ti-action-menu-item disabled" href="{{$.RepoLink}}/modelarts/train-job/{{.JobID}}/create_version?version_name={{.VersionName}}">{{$.i18n.Tr "repo.modelarts.modify"}}</a> | <a class="ti-action-menu-item disabled" href="{{$.RepoLink}}/modelarts/train-job/{{.JobID}}/create_version?version_name={{.VersionName}}">{{$.i18n.Tr "repo.modelarts.modify"}}</a> | ||||
| {{end}} | {{end}} | ||||
| {{$.CsrfTokenHtml}} | {{$.CsrfTokenHtml}} | ||||
| {{if $.Permission.CanWrite $.UnitTypeCloudBrain}} | |||||
| {{if .CanDel}} | |||||
| <a class="ti-action-menu-item {{if eq .Status "KILLED" "FAILED" "START_FAILED" "KILLING" "COMPLETED"}}disabled {{end}}" id="{{.VersionName}}-stop" onclick="stopVersion({{.VersionName}})">{{$.i18n.Tr "repo.stop"}}</a> | <a class="ti-action-menu-item {{if eq .Status "KILLED" "FAILED" "START_FAILED" "KILLING" "COMPLETED"}}disabled {{end}}" id="{{.VersionName}}-stop" onclick="stopVersion({{.VersionName}})">{{$.i18n.Tr "repo.stop"}}</a> | ||||
| {{else}} | {{else}} | ||||
| <a class="ti-action-menu-item disabled" id="{{.VersionName}}-stop" onclick="stopVersion({{.VersionName}})">{{$.i18n.Tr "repo.stop"}}</a> | <a class="ti-action-menu-item disabled" id="{{.VersionName}}-stop" onclick="stopVersion({{.VersionName}})">{{$.i18n.Tr "repo.stop"}}</a> | ||||
| {{end}} | {{end}} | ||||
| {{$.CsrfTokenHtml}} | {{$.CsrfTokenHtml}} | ||||
| {{if $.Permission.CanWrite $.UnitTypeCloudBrain}} | |||||
| {{if .CanDel}} | |||||
| <a class="ti-action-menu-item" onclick="deleteVersion({{.VersionName}})" style="color: #FF4D4F;">{{$.i18n.Tr "repo.delete"}}</a> | <a class="ti-action-menu-item" onclick="deleteVersion({{.VersionName}})" style="color: #FF4D4F;">{{$.i18n.Tr "repo.delete"}}</a> | ||||
| {{else}} | {{else}} | ||||
| <a class="ti-action-menu-item disabled" onclick="deleteVersion({{.VersionName}})" style="color: #FF4D4F;">{{$.i18n.Tr "repo.delete"}}</a> | <a class="ti-action-menu-item disabled" onclick="deleteVersion({{.VersionName}})" style="color: #FF4D4F;">{{$.i18n.Tr "repo.delete"}}</a> | ||||
| @@ -243,12 +241,11 @@ td, th { | |||||
| <tbody class="ti-text-form"> | <tbody class="ti-text-form"> | ||||
| <tr class="ti-no-ng-animate"> | <tr class="ti-no-ng-animate"> | ||||
| <td class="ti-no-ng-animate ti-text-form-label text-width80"> | <td class="ti-no-ng-animate ti-text-form-label text-width80"> | ||||
| {{$.i18n.Tr "repo.cloudbrain_task"}} | |||||
| {{$.i18n.Tr "repo.cloudbrain_task"}} | |||||
| </td> | </td> | ||||
| <td class="ti-text-form-content"> | <td class="ti-text-form-content"> | ||||
| <div class="text-span text-span-w"> | <div class="text-span text-span-w"> | ||||
| {{.JobName}} | |||||
| {{.JobName}} | |||||
| </div> | </div> | ||||
| </td> | </td> | ||||
| </tr> | </tr> | ||||
| @@ -259,7 +256,7 @@ td, th { | |||||
| <td class="ti-text-form-content"> | <td class="ti-text-form-content"> | ||||
| <div class="text-span text-span-w" id="{{.VersionName}}-status"> | <div class="text-span text-span-w" id="{{.VersionName}}-status"> | ||||
| {{.Status}} | |||||
| {{.Status}} | |||||
| </div> | </div> | ||||
| </td> | </td> | ||||
| </tr> | </tr> | ||||
| @@ -270,7 +267,7 @@ td, th { | |||||
| <td class="ti-text-form-content"> | <td class="ti-text-form-content"> | ||||
| <div class="text-span text-span-w"> | <div class="text-span text-span-w"> | ||||
| {{.VersionName}} | |||||
| {{.VersionName}} | |||||
| </div> | </div> | ||||
| </td> | </td> | ||||
| </tr> | </tr> | ||||
| @@ -287,7 +284,7 @@ td, th { | |||||
| </tr> | </tr> | ||||
| <tr class="ti-no-ng-animate"> | <tr class="ti-no-ng-animate"> | ||||
| <td class="ti-no-ng-animate ti-text-form-label text-width80"> | <td class="ti-no-ng-animate ti-text-form-label text-width80"> | ||||
| {{$.i18n.Tr "repo.modelarts.train_job.dura_time"}} | |||||
| {{$.i18n.Tr "repo.modelarts.train_job.dura_time"}} | |||||
| </td> | </td> | ||||
| <td class="ti-text-form-content"> | <td class="ti-text-form-content"> | ||||
| @@ -309,9 +306,8 @@ td, th { | |||||
| </tr> | </tr> | ||||
| <tr class="ti-no-ng-animate"> | <tr class="ti-no-ng-animate"> | ||||
| <td class="ti-no-ng-animate ti-text-form-label text-width80"> | <td class="ti-no-ng-animate ti-text-form-label text-width80"> | ||||
| {{$.i18n.Tr "repo.modelarts.train_job.compute_node"}} | |||||
| {{$.i18n.Tr "repo.modelarts.train_job.compute_node"}} | |||||
| </td> | </td> | ||||
| <td class="ti-text-form-content"> | <td class="ti-text-form-content"> | ||||
| <div class="text-span text-span-w"> | <div class="text-span text-span-w"> | ||||
| {{.WorkServerNumber}} | {{.WorkServerNumber}} | ||||
| @@ -326,9 +322,8 @@ td, th { | |||||
| <tbody class="ti-text-form"> | <tbody class="ti-text-form"> | ||||
| <tr class="ti-no-ng-animate"> | <tr class="ti-no-ng-animate"> | ||||
| <td class="ti-no-ng-animate ti-text-form-label text-width80"> | <td class="ti-no-ng-animate ti-text-form-label text-width80"> | ||||
| {{$.i18n.Tr "repo.modelarts.train_job.AI_driver"}} | |||||
| {{$.i18n.Tr "repo.modelarts.train_job.AI_driver"}} | |||||
| </td> | </td> | ||||
| <td class="ti-text-form-content"> | <td class="ti-text-form-content"> | ||||
| <div class="text-span text-span-w"> | <div class="text-span text-span-w"> | ||||
| {{.EngineName}} | {{.EngineName}} | ||||
| @@ -348,12 +343,12 @@ td, th { | |||||
| </tr> | </tr> | ||||
| <tr class="ti-no-ng-animate"> | <tr class="ti-no-ng-animate"> | ||||
| <td class="ti-no-ng-animate ti-text-form-label text-width80"> | <td class="ti-no-ng-animate ti-text-form-label text-width80"> | ||||
| {{$.i18n.Tr "repo.modelarts.train_job.start_file"}} | |||||
| {{$.i18n.Tr "repo.modelarts.train_job.start_file"}} | |||||
| </td> | </td> | ||||
| <td class="ti-text-form-content"> | <td class="ti-text-form-content"> | ||||
| <div class="text-span text-span-w"> | <div class="text-span text-span-w"> | ||||
| {{.BootFile}} | |||||
| {{.BootFile}} | |||||
| </div> | </div> | ||||
| </td> | </td> | ||||
| </tr> | </tr> | ||||
| @@ -379,17 +374,7 @@ td, th { | |||||
| </div> | </div> | ||||
| </td> | </td> | ||||
| </tr> | </tr> | ||||
| <!-- <tr class="ti-no-ng-animate"> | |||||
| <td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
| 训练输出位置 | |||||
| </td> | |||||
| <td class="ti-text-form-content"> | |||||
| <div class="text-span text-span-w"> | |||||
| {{.TrainUrl}} | |||||
| </div> | |||||
| </td> | |||||
| </tr> --> | |||||
| </tr> | |||||
| <tr class="ti-no-ng-animate"> | <tr class="ti-no-ng-animate"> | ||||
| <td class="ti-no-ng-animate ti-text-form-label text-width80"> | <td class="ti-no-ng-animate ti-text-form-label text-width80"> | ||||
| {{$.i18n.Tr "repo.modelarts.train_job.description"}} | {{$.i18n.Tr "repo.modelarts.train_job.description"}} | ||||
| @@ -414,15 +399,7 @@ td, th { | |||||
| <div class="ui message message{{.VersionName}}" style="display: none;"> | <div class="ui message message{{.VersionName}}" style="display: none;"> | ||||
| <div id="header"></div> | <div id="header"></div> | ||||
| </div> | </div> | ||||
| <!-- <div class="ui top attached segment" style="background: #f0f0f0;"> | |||||
| <div class="center aligned"> | |||||
| <label>{{$.i18n.Tr "repo.modelarts.log"}}:</label> | |||||
| </div> | |||||
| </div> --> | |||||
| <div class="ui attached log" onscroll="logScroll({{.VersionName}})" id="log{{.VersionName}}" style="height: 300px !important; overflow: auto;"> | <div class="ui attached log" onscroll="logScroll({{.VersionName}})" id="log{{.VersionName}}" style="height: 300px !important; overflow: auto;"> | ||||
| <!-- <input type="hidden" class="version_name" name="version_name" value={{.VersionName}}> --> | |||||
| <input type="hidden" name="end_line" value> | <input type="hidden" name="end_line" value> | ||||
| <input type="hidden" name="start_line" value> | <input type="hidden" name="start_line" value> | ||||
| <pre id="log_file{{.VersionName}}"></pre> | <pre id="log_file{{.VersionName}}"></pre> | ||||
| @@ -474,9 +451,7 @@ td, th { | |||||
| <script> | <script> | ||||
| console.log({{.version_list_task}}) | console.log({{.version_list_task}}) | ||||
| console.log({{.}}) | |||||
| $('.menu .item').tab() | $('.menu .item').tab() | ||||
| // $('.ui.style.accordion').accordion(); | |||||
| $(document).ready(function(){ | $(document).ready(function(){ | ||||
| $('.ui.accordion').accordion({selector:{trigger:'.icon'}}); | $('.ui.accordion').accordion({selector:{trigger:'.icon'}}); | ||||
| @@ -503,8 +478,6 @@ td, th { | |||||
| e.cancelBubble = true; //ie兼容 | e.cancelBubble = true; //ie兼容 | ||||
| } | } | ||||
| } | } | ||||
| // let timeid = window.setInterval(refreshStatus(version_name), 30000); | |||||
| // document.ready(refreshStatus(version_name)) | |||||
| let timeid = window.setInterval(loadJobStatus, 30000); | let timeid = window.setInterval(loadJobStatus, 30000); | ||||
| $(document).ready(loadJobStatus); | $(document).ready(loadJobStatus); | ||||
| @@ -574,7 +547,12 @@ td, th { | |||||
| }, | }, | ||||
| onApprove: function() { | onApprove: function() { | ||||
| $.post(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/del_version`,{version_name:version_name},(data)=>{ | $.post(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/del_version`,{version_name:version_name},(data)=>{ | ||||
| $('#accordion'+version_name).remove() | |||||
| if(data.VersionListCount===0){ | |||||
| location.href=`/${userName}/${repoPath}/modelarts/train-job` | |||||
| }else{ | |||||
| $('#accordion'+version_name).remove() | |||||
| } | |||||
| }).fail(function(err) { | }).fail(function(err) { | ||||
| console.log(err); | console.log(err); | ||||
| }); | }); | ||||
| @@ -658,12 +636,6 @@ td, th { | |||||
| } | } | ||||
| } | } | ||||
| function downloadModelFile(version_name,filename){ | |||||
| $.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/model_download?version_name=${version_name}&file_name=${filename}`, (data) => { | |||||
| console.log(data) | |||||
| }) | |||||
| } | |||||
| function renderDir(data,version_name){ | function renderDir(data,version_name){ | ||||
| let html="" | let html="" | ||||
| html += "<div class='ui grid' style='margin:0;'>" | html += "<div class='ui grid' style='margin:0;'>" | ||||
| @@ -49,87 +49,6 @@ | |||||
| text-align: center; | text-align: center; | ||||
| color: #C2C7CC;" | color: #C2C7CC;" | ||||
| } | } | ||||
| #mask { | |||||
| position: fixed; | |||||
| top: 0px; | |||||
| left: 0px; | |||||
| right: 0px; | |||||
| bottom: 0px; | |||||
| filter: alpha(opacity=60); | |||||
| background-color: #777; | |||||
| z-index: 1000; | |||||
| display: none; | |||||
| opacity: 0.8; | |||||
| -moz-opacity: 0.5; | |||||
| padding-top: 100px; | |||||
| color: #000000 | |||||
| } | |||||
| /* 加载圈css效果图 */ | |||||
| #loadingPage { | |||||
| margin: 200px auto; | |||||
| width: 50px; | |||||
| height: 40px; | |||||
| text-align: center; | |||||
| font-size: 10px; | |||||
| display: block; | |||||
| } | |||||
| #loadingPage>div { | |||||
| background-color: green; | |||||
| height: 100%; | |||||
| width: 6px; | |||||
| display: inline-block; | |||||
| -webkit-animation: sk-stretchdelay 1.2s infinite ease-in-out; | |||||
| animation: sk-stretchdelay 1.2s infinite ease-in-out; | |||||
| } | |||||
| #loadingPage .rect2 { | |||||
| -webkit-animation-delay: -1.1s; | |||||
| animation-delay: -1.1s; | |||||
| } | |||||
| #loadingPage .rect3 { | |||||
| -webkit-animation-delay: -1.0s; | |||||
| animation-delay: -1.0s; | |||||
| } | |||||
| #loadingPage .rect4 { | |||||
| -webkit-animation-delay: -0.9s; | |||||
| animation-delay: -0.9s; | |||||
| } | |||||
| #loadingPage .rect5 { | |||||
| -webkit-animation-delay: -0.8s; | |||||
| animation-delay: -0.8s; | |||||
| } | |||||
| .left2{ | |||||
| margin-left: -2px; | |||||
| } | |||||
| @-webkit-keyframes sk-stretchdelay { | |||||
| 0%, | |||||
| 40%, | |||||
| 100% { | |||||
| -webkit-transform: scaleY(0.4) | |||||
| } | |||||
| 20% { | |||||
| -webkit-transform: scaleY(1.0) | |||||
| } | |||||
| } | |||||
| @keyframes sk-stretchdelay { | |||||
| 0%, | |||||
| 40%, | |||||
| 100% { | |||||
| transform: scaleY(0.4); | |||||
| -webkit-transform: scaleY(0.4); | |||||
| } | |||||
| 20% { | |||||
| transform: scaleY(1.0); | |||||
| -webkit-transform: scaleY(1.0); | |||||
| } | |||||
| } | |||||
| </style> | </style> | ||||
| <!-- <div class="ui page dimmer"> | <!-- <div class="ui page dimmer"> | ||||
| @@ -240,6 +159,7 @@ | |||||
| <span> | <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> | <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> | </span> | ||||
| <a href="https://git.openi.org.cn/OpenIOSSG/MINIST_Example" target="_blank">查看样例</a> | |||||
| </div> | </div> | ||||
| <div class="required unite min_title inline field"> | <div class="required unite min_title inline field"> | ||||
| <label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.dataset"}}</label> | <label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.dataset"}}</label> | ||||
| @@ -254,6 +174,7 @@ | |||||
| {{end}} | {{end}} | ||||
| {{end}} | {{end}} | ||||
| </select> | </select> | ||||
| <span class="tooltips">数据集位置存储在环境变量data_url中,训练输出路径存储在环境变量train_url中。</span> | |||||
| </div> | </div> | ||||
| <div class="inline unite min_title field"> | <div class="inline unite min_title field"> | ||||
| @@ -0,0 +1,240 @@ | |||||
| <!-- 头部导航栏 --> | |||||
| {{template "base/head" .}} | |||||
| <!-- 弹窗 --> | |||||
| <div id="mask"> | |||||
| <div id="loadingPage"> | |||||
| <div class="rect1"></div> | |||||
| <div class="rect2"></div> | |||||
| <div class="rect3"></div> | |||||
| <div class="rect4"></div> | |||||
| <div class="rect5"></div> | |||||
| </div> | |||||
| </div> | |||||
| {{$repository := .Repository.ID}} | |||||
| <!-- 提示框 --> | |||||
| <div class="alert"></div> | |||||
| <div class="repository release dataset-list view"> | |||||
| {{template "repo/header" .}} | |||||
| <!-- 列表容器 --> | |||||
| <div class="ui container active loader" id="loadContainer"> | |||||
| {{template "base/alert" .}} | |||||
| <div class="ui two column stackable grid" style="display: none;"> | |||||
| <div class="column"></div> | |||||
| <div class="column right aligned"> | |||||
| <!-- --> | |||||
| <a class="ui button {{if .Permission.CanWrite $.UnitTypeCloudBrain}} green {{else}} disabled {{end}}" onclick="showcreate(this)">{{$.i18n.Tr "repo.model.manage.import_new_model"}}</a> | |||||
| </div> | |||||
| </div> | |||||
| <!-- 中下列表展示区 --> | |||||
| <div class="ui grid" style="display: none;"> | |||||
| <div class="row" style="padding-top: 0;"> | |||||
| <div class="ui sixteen wide column"> | |||||
| <!-- 任务展示 --> | |||||
| <div class="dataset list" id="model_list"> | |||||
| <!-- 表头 --> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <!-- div full height--> | |||||
| </div> | |||||
| <!-- 确认模态框 --> | |||||
| <div id="deletemodel"> | |||||
| <div class="ui basic modal first"> | |||||
| <div class="ui icon header"> | |||||
| <i class="trash icon"></i> 删除模型 | |||||
| </div> | |||||
| <div class="content"> | |||||
| <p>你确认删除该模型么?此模型一旦删除不可恢复。</p> | |||||
| </div> | |||||
| <div class="actions"> | |||||
| <div class="ui red basic inverted cancel button"> | |||||
| <i class="remove icon"></i> 取消操作 | |||||
| </div> | |||||
| <div class="ui green basic inverted ok button"> | |||||
| <i class="checkmark icon"></i> 确定操作 | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div id="newmodel"> | |||||
| <div class="ui modal second"> | |||||
| <div class="header" style="padding: 1rem;background-color: rgba(240, 240, 240, 100);"> | |||||
| <h4 id="model_header"></h4> | |||||
| </div> | |||||
| <div class="content content-padding"> | |||||
| <form id="formId" method="POST" class="ui form"> | |||||
| <div class="ui error message"> | |||||
| <!-- <p>asdasdasd</p> --> | |||||
| </div> | |||||
| <input type="hidden" name="_csrf" value=""> | |||||
| <div class="two inline fields "> | |||||
| <div class="required ten wide field"> | |||||
| <label style="margin-left: -23px;">选择训练任务</label> | |||||
| <div class="ui dropdown selection search width83 loading" id="choice_model"> | |||||
| <input type="hidden" id="JobId" name="JobId" required> | |||||
| <div class="default text">选择训练任务</div> | |||||
| <i class="dropdown icon"></i> | |||||
| <div class="menu" id="job-name"> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div class="required six widde field"> | |||||
| <label>版本</label> | |||||
| <div class="ui dropdown selection search width70" id="choice_version"> | |||||
| <input type="hidden" id="VersionName" name="VersionName" required> | |||||
| <div class="default text">选择版本</div> | |||||
| <i class="dropdown icon"></i> | |||||
| <div class="menu" id="job-version"> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div class="required inline field" id="modelname"> | |||||
| <label>模型名称</label> | |||||
| <input style="width: 45%;" id="name" name="Name" required maxlength="25" onkeyup="this.value=this.value.replace(/[, ]/g,'')"> | |||||
| </div> | |||||
| <div class="required inline field" id="verionname"> | |||||
| <label>模型版本</label> | |||||
| <input style="width: 45%;" id="version" name="Version" value="" readonly required maxlength="255"> | |||||
| </div> | |||||
| <div class="inline field"> | |||||
| <label>模型标签</label> | |||||
| <input style="width: 83%;margin-left: 7px;" id="label" name="Label" maxlength="255" placeholder='{{.i18n.Tr "repo.modelarts.train_job.label_place"}}'> | |||||
| </div> | |||||
| <div class="inline field"> | |||||
| <label for="description">模型描述</label> | |||||
| <textarea style="width: 83%;margin-left: 7px;" id="Description" name="Description" rows="3" maxlength="255" placeholder='{{.i18n.Tr "repo.modelarts.train_job.new_place"}}' onchange="this.value=this.value.substring(0, 255)" onkeydown="this.value=this.value.substring(0, 255)" onkeyup="this.value=this.value.substring(0, 256)"></textarea> | |||||
| </div> | |||||
| <div class="inline field" style="margin-left: 75px;"> | |||||
| <button id="submitId" type="button" class="ui create_train_job green button" style="position: absolute;"> | |||||
| {{.i18n.Tr "repo.model.manage.sava_model"}} | |||||
| </button> | |||||
| </div> | |||||
| </form> | |||||
| <div class="actions" style="display: inline-block;margin-left: 180px;"> | |||||
| <button class="ui button cancel" >{{.i18n.Tr "repo.cloudbrain.cancel"}}</button> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| {{template "base/footer" .}} | |||||
| <script> | |||||
| let repolink = {{.RepoLink}} | |||||
| let repoId = {{$repository}} | |||||
| let url_href = window.location.pathname.split('show_model')[0] + 'create_model' | |||||
| const {_AppSubUrl, _StaticUrlPrefix, csrf} = window.config; | |||||
| $('input[name="_csrf"]').val(csrf) | |||||
| function createModelName(){ | |||||
| let repoName = location.pathname.split('/')[2] | |||||
| let modelName = repoName + '_model_' + Math.random().toString(36).substr(2, 4) | |||||
| $('#name').val(modelName) | |||||
| $('#version').val("0.0.1") | |||||
| } | |||||
| function showcreate(obj){ | |||||
| $('.ui.modal.second') | |||||
| .modal({ | |||||
| centered: false, | |||||
| onShow:function(){ | |||||
| $('#model_header').text("导入新模型") | |||||
| $('input[name="Version"]').addClass('model_disabled') | |||||
| $('.ui.dimmer').css({"background-color":"rgb(136, 136, 136,0.7)"}) | |||||
| $("#job-name").empty() | |||||
| createModelName() | |||||
| loadTrainList() | |||||
| }, | |||||
| onHide:function(){ | |||||
| document.getElementById("formId").reset(); | |||||
| $('#choice_model').dropdown('clear') | |||||
| $('#choice_version').dropdown('clear') | |||||
| $('.ui.dimmer').css({"background-color":""}) | |||||
| $('.ui.error.message').text() | |||||
| $('.ui.error.message').css('display','none') | |||||
| } | |||||
| }) | |||||
| .modal('show') | |||||
| } | |||||
| $(function(){ | |||||
| $('#choice_model').dropdown({ | |||||
| onChange:function(value){ | |||||
| $(".ui.dropdown.selection.search.width70").addClass("loading") | |||||
| $('#choice_version').dropdown('clear') | |||||
| $("#job-version").empty() | |||||
| loadTrainVersion(value) | |||||
| } | |||||
| }) | |||||
| }) | |||||
| function versionAdd(version){ | |||||
| let versionArray = version.split('.') | |||||
| if(versionArray[2]=='9'){ | |||||
| if(versionArray[1]=='9'){ | |||||
| versionArray[0] = String(Number(versionArray[1])+1) | |||||
| versionArray[1] = '0' | |||||
| }else{ | |||||
| versionArray[1]=String(Number(versionArray[1])+1) | |||||
| } | |||||
| versionArray[2]='0' | |||||
| }else{ | |||||
| versionArray[2]=String(Number(versionArray[2])+1) | |||||
| } | |||||
| return versionArray.join('.') | |||||
| } | |||||
| function loadTrainList(){ | |||||
| $.get(`${repolink}/modelmanage/query_train_job?repoId=${repoId}`, (data) => { | |||||
| const n_length = data.length | |||||
| let train_html='' | |||||
| for (let i=0;i<n_length;i++){ | |||||
| train_html += `<div class="item" data-value="${data[i].JobID}">${data[i].JobName}</div>` | |||||
| train_html += '</div>' | |||||
| } | |||||
| $("#job-name").append(train_html) | |||||
| $(".ui.dropdown.selection.search.width83").removeClass("loading") | |||||
| $('#choice_model .default.text').text(data[0].JobName) | |||||
| $('#choice_model input[name="JobId"]').val(data[0].JobID) | |||||
| loadTrainVersion() | |||||
| }) | |||||
| } | |||||
| function loadTrainVersion(value){ | |||||
| let JobID = !value ?$('#choice_model input[name="JobId"]').val(): value | |||||
| $.get(`${repolink}/modelmanage/query_train_job_version?JobID=${JobID}`, (data) => { | |||||
| const n_length = data.length | |||||
| let train_html='' | |||||
| for (let i=0;i<n_length;i++){ | |||||
| train_html += `<div class="item" data-value="${data[i].VersionName}">${data[i].VersionName}</div>` | |||||
| train_html += '</div>' | |||||
| } | |||||
| if(data.length){ | |||||
| $("#job-version").append(train_html) | |||||
| $(".ui.dropdown.selection.search.width70").removeClass("loading") | |||||
| $('#choice_version .default.text').text(data[0].VersionName) | |||||
| $('#choice_version input[name="VersionName"]').val(data[0].VersionName) | |||||
| } | |||||
| }) | |||||
| } | |||||
| </script> | |||||
| @@ -0,0 +1,279 @@ | |||||
| {{template "base/head" .}} | |||||
| <div class="repository"> | |||||
| {{template "repo/header" .}} | |||||
| <style> | |||||
| .model_header_text{ | |||||
| font-size: 14px; | |||||
| color: #101010; | |||||
| font-weight: bold; | |||||
| } | |||||
| .ti_form{ | |||||
| text-align: left; | |||||
| max-width: 100%; | |||||
| vertical-align: middle; | |||||
| } | |||||
| .ti-text-form-label { | |||||
| padding-bottom: 20px; | |||||
| padding-right: 20px; | |||||
| color: #8a8e99; | |||||
| font-size: 14px; | |||||
| white-space: nowrap !important; | |||||
| width: 80px; | |||||
| line-height: 30px; | |||||
| } | |||||
| .ti-text-form-content { | |||||
| line-height: 30px; | |||||
| padding-bottom: 20px; | |||||
| width: 100%; | |||||
| } | |||||
| .change-version{ | |||||
| min-width: auto !important; | |||||
| border: 1px solid rgba(187, 187, 187, 100) !important; | |||||
| border-radius: .38571429rem !important; | |||||
| margin-left: 1.5em; | |||||
| } | |||||
| .title-word-elipsis{ | |||||
| overflow: hidden; | |||||
| text-overflow: ellipsis; | |||||
| white-space: nowrap; | |||||
| width: 30%; | |||||
| } | |||||
| .word-elipsis{ | |||||
| overflow: hidden; | |||||
| text-overflow: ellipsis; | |||||
| white-space: nowrap; | |||||
| padding-right: 80px; | |||||
| } | |||||
| .half-table{ | |||||
| width: 50%; | |||||
| float: left; | |||||
| } | |||||
| .text-width80 { | |||||
| width: 100px; | |||||
| line-height: 30px; | |||||
| } | |||||
| .tableStyle{ | |||||
| width:100%; | |||||
| table-layout: fixed; | |||||
| } | |||||
| .iword-elipsis{ | |||||
| display: inline-block; | |||||
| width: 80%; | |||||
| overflow: hidden; | |||||
| text-overflow: ellipsis; | |||||
| white-space: nowrap; | |||||
| } | |||||
| </style> | |||||
| <div class="ui container"> | |||||
| <h4 class="ui header" id="vertical-segment"> | |||||
| <!-- <a href="javascript:window.history.back();"><i class="arrow left icon"></i>返回</a> --> | |||||
| <div class="ui breadcrumb"> | |||||
| <a class="section" href="{{$.RepoLink}}/modelmanage/show_model"> | |||||
| 模型管理 | |||||
| </a> | |||||
| <div class="divider"> / </div> | |||||
| <div class="active section">{{.name}}</div> | |||||
| </div> | |||||
| <select class="ui dropdown tiny change-version" id="dropdown" onchange="changeInfo(this.value)"> | |||||
| </select> | |||||
| </h4> | |||||
| <div id="showInfo" style="border:1px solid #e2e2e2;padding: 20px 60px;margin-top:24px"> | |||||
| <div class="half-table"> | |||||
| <span class="model_header_text">基本信息</span> | |||||
| <table class="tableStyle" style="margin-top:20px;"> | |||||
| <tbody> | |||||
| <tr> | |||||
| <td class="ti-text-form-label text-width80">模型名称</td> | |||||
| <td class="ti-text-form-content word-elipsis"><span id="ModelName" title=""></span></td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td class="ti-text-form-label text-width80">版本</td> | |||||
| <td class="ti-text-form-content word-elipsis"><span id="Version" title=""></span></td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td class="ti-text-form-label text-width80">标签</td> | |||||
| <td class="ti-text-form-content"> | |||||
| <div id="Label" style="overflow: hidden;width: 95%;"> | |||||
| </div> | |||||
| </td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td class="ti-text-form-label text-width80">大小</td> | |||||
| <td class="ti-text-form-content word-elipsis"><span id="Size" title=""></span></td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td class="ti-text-form-label text-width80">创建时间</td> | |||||
| <td class="ti-text-form-content word-elipsis"><span id="CreateTime" title=""></span></td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td class="ti-text-form-label text-width80">模型描述</td> | |||||
| <td class="ti-text-form-content" ><div id="edit-td" style="display:flex"><span id="Description" title="" class="iword-elipsis"></span><i id="edit-pencil" data-id="" data-desc="" class="pencil alternate icon" style="cursor:pointer;vertical-align: top;" id="editor" onclick="editorFn(this)"></div></td> | |||||
| </tr> | |||||
| </tbody> | |||||
| </table> | |||||
| </div> | |||||
| <div class="half-table"> | |||||
| <span class="model_header_text">模型精度</span> | |||||
| <table class="tableStyle" style="margin-top:20px;"> | |||||
| <tbody> | |||||
| <tr> | |||||
| <td class="ti-text-form-label text-width80">准确率</td> | |||||
| <td class="ti-text-form-content word-elipsis"><span id="Accuracy" title=""></span></td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td class="ti-text-form-label text-width80">F1</td> | |||||
| <td class="ti-text-form-content word-elipsis"><span id="F1" title=""></span></td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td class="ti-text-form-label text-width80">精确率</td> | |||||
| <td class="ti-text-form-content word-elipsis"><span id="Precision" title=""></span></td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td class="ti-text-form-label text-width80">召回率</td> | |||||
| <td class="ti-text-form-content word-elipsis"><span id="Recall" title=""></span></td> | |||||
| </tr> | |||||
| </tbody> | |||||
| </table> | |||||
| </div> | |||||
| <div style="clear: both;"></div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| {{template "base/footer" .}} | |||||
| <script> | |||||
| let url = location.href.split('show_model')[0] | |||||
| let ID = location.search.split('?name=').pop() | |||||
| $(document).ready(loadInfo); | |||||
| function changeInfo(version){ | |||||
| $.get(`${url}show_model_info_api?name=${ID}`,(data)=>{ | |||||
| let versionData = data.filter((item)=>{ | |||||
| return item.Version === version | |||||
| }) | |||||
| let returnArray = [] | |||||
| returnArray = transObj(versionData) | |||||
| let [initObj,initModelAcc,id] = returnArray | |||||
| renderInfo(initObj,initModelAcc,id) | |||||
| }) | |||||
| } | |||||
| function loadInfo(){ | |||||
| $.get(`${url}show_model_info_api?name=${ID}`,(data)=>{ | |||||
| let html = '' | |||||
| for (let i=0;i<data.length;i++){ | |||||
| if(!data[i].IsCanOper){ | |||||
| $("#edit-pencil").css("display","none") | |||||
| } | |||||
| html += `<option value="${data[i].Version}">${data[i].Version}</option>` | |||||
| } | |||||
| $('#dropdown').append(html) | |||||
| let returnArray = [] | |||||
| returnArray = transObj(data) | |||||
| let [initObj,initModelAcc,id] = returnArray | |||||
| renderInfo(initObj,initModelAcc,id) | |||||
| }) | |||||
| } | |||||
| function transObj(data){ | |||||
| let {ID,Name,Version,Label,Size,Description,CreatedUnix,Accuracy} = data[0] | |||||
| let modelAcc = JSON.parse(Accuracy) | |||||
| let size = tranSize(Size) | |||||
| let time = transTime(CreatedUnix) | |||||
| let initObj = { | |||||
| ModelName:Name || '--', | |||||
| Version:Version, | |||||
| Label:Label || '--', | |||||
| Size:size, | |||||
| CreateTime:time, | |||||
| Description:Description || '--', | |||||
| } | |||||
| let initModelAcc = { | |||||
| Accuracy: modelAcc.Accuracy || '--', | |||||
| F1: modelAcc.F1 || '--', | |||||
| Precision:modelAcc.Precision || '--', | |||||
| Recall: modelAcc.Recall || '--' | |||||
| } | |||||
| return [initObj,initModelAcc,ID] | |||||
| } | |||||
| function transTime(time){ | |||||
| let date = new Date(time * 1000);//时间戳为10位需*1000,时间戳为13位的话不需乘1000 | |||||
| let Y = date.getFullYear() + '-'; | |||||
| let M = (date.getMonth()+1 < 10 ? '0'+(date.getMonth()+1):date.getMonth()+1) + '-'; | |||||
| let D = (date.getDate()< 10 ? '0'+date.getDate():date.getDate())+ ' '; | |||||
| let h = (date.getHours() < 10 ? '0'+date.getHours():date.getHours())+ ':'; | |||||
| let m = (date.getMinutes() < 10 ? '0'+date.getMinutes():date.getMinutes()) + ':'; | |||||
| let s = date.getSeconds() < 10 ? '0'+date.getSeconds():date.getSeconds(); | |||||
| return Y+M+D+h+m+s; | |||||
| } | |||||
| function tranSize(value){ | |||||
| if(null==value||value==''){ | |||||
| return "0 Bytes"; | |||||
| } | |||||
| var unitArr = new Array("Bytes","KB","MB","GB","TB","PB","EB","ZB","YB"); | |||||
| var index=0; | |||||
| var srcsize = parseFloat(value); | |||||
| index=Math.floor(Math.log(srcsize)/Math.log(1024)); | |||||
| var size =srcsize/Math.pow(1024,index); | |||||
| size=size.toFixed(2);//保留的小数位数 | |||||
| return size+unitArr[index]; | |||||
| } | |||||
| function editorFn(context){ | |||||
| let id= context.dataset.id | |||||
| let text = context.dataset.desc | |||||
| console.log(id,text) | |||||
| $('#edit-td').replaceWith("<div id='edit-div' style='width:80%;display: inline-block;'><textarea id='textarea-value' value='' rows='3' maxlength='255' style='width:80%;' id='edit-text'>"+text+"</textarea><i class='check icon' style='color: #50d4ab;' onclick='editorSure(\"" + text + "\",\"" + id + "\")'></i><i class='times icon' style='color: #f66f6a;' onclick='editorCancel(\"" + text + "\",\"" + id + "\")'></i></div>"); | |||||
| } | |||||
| function editorCancel(text,id){ | |||||
| $('#edit-div').replaceWith(`<div id="edit-td" style="display:flex;"><span id="Description" title="${text}" class="iword-elipsis">${text}</span><i id="edit-pencil" data-id="${id}" data-desc="${text}" class="pencil alternate icon" style="cursor:pointer;vertical-align: top;" id="editor" onclick="editorFn(this)"></div>`) | |||||
| } | |||||
| function editorSure(text,id){ | |||||
| let description=$('#textarea-value').val() | |||||
| let data = { | |||||
| ID:id, | |||||
| Description:description | |||||
| } | |||||
| $.ajax({ | |||||
| url:`${url}modify_model`, | |||||
| type:'PUT', | |||||
| data:data | |||||
| }).done((res)=>{ | |||||
| $('#edit-div').replaceWith(`<div id="edit-td" style="display:flex;"><span id="Description" title="${description}" class="iword-elipsis">${description}</span><i id="edit-pencil" data-id="${id}" data-desc="${description}" class="pencil alternate icon" style="cursor:pointer;vertical-align: top;" id="editor" onclick="editorFn(this)"></div>`) | |||||
| }) | |||||
| } | |||||
| function renderInfo(obj,accObj,id){ | |||||
| for(let key in obj){ | |||||
| if(key==="Description"){ | |||||
| $(`#${key}`).text(obj[key]) | |||||
| $(`#${key}`).attr("title",obj[key]) | |||||
| $('#edit-pencil').attr("data-id",id) | |||||
| $('#edit-pencil').attr("data-desc",obj[key]) | |||||
| } | |||||
| else if(key==="Label"){ | |||||
| $('#Label').empty() | |||||
| if(obj[key]==='--'){ | |||||
| $('#Label').text(obj[key]) | |||||
| }else{ | |||||
| let labelArray = obj[key].trim().replace(/ +/g,' ').split(' ') | |||||
| let html='' | |||||
| for(let i=0;i<labelArray.length;i++){ | |||||
| html += `<a class="ui label" title="${labelArray[i]}">${labelArray[i]}</a>` | |||||
| } | |||||
| $('#Label').append(html) | |||||
| } | |||||
| } | |||||
| else{ | |||||
| $(`#${key}`).text(obj[key]) | |||||
| $(`#${key}`).attr("title",obj[key]) | |||||
| } | |||||
| } | |||||
| for(let key in accObj){ | |||||
| $(`#${key}`).text(accObj[key]) | |||||
| $(`#${key}`).attr("title",accObj[key]) | |||||
| } | |||||
| } | |||||
| </script> | |||||
| @@ -149,7 +149,14 @@ | |||||
| <label>{{.i18n.Tr "repo.settings.dataset_desc"}}</label> | <label>{{.i18n.Tr "repo.settings.dataset_desc"}}</label> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| {{$isModelMangeEnabled := .Repository.UnitEnabled $.UnitTypeModelManage }} | |||||
| <div class="inline field"> | |||||
| <label>{{.i18n.Tr "repo.model_manager"}}</label> | |||||
| <div class="ui checkbox"> | |||||
| <input class="enable-system" name="enable_model_manager" type="checkbox" {{if $isModelMangeEnabled}}checked{{end}}> | |||||
| <label>{{.i18n.Tr "repo.settings.model_desc"}}</label> | |||||
| </div> | |||||
| </div> | |||||
| {{$isCloudBrainEnabled := .Repository.UnitEnabled $.UnitTypeCloudBrain }} | {{$isCloudBrainEnabled := .Repository.UnitEnabled $.UnitTypeCloudBrain }} | ||||
| <div class="inline field"> | <div class="inline field"> | ||||
| <label>{{.i18n.Tr "repo.cloudbrain"}}</label> | <label>{{.i18n.Tr "repo.cloudbrain"}}</label> | ||||
| @@ -158,7 +165,6 @@ | |||||
| <label>{{.i18n.Tr "repo.settings.cloudbrain_desc"}}</label> | <label>{{.i18n.Tr "repo.settings.cloudbrain_desc"}}</label> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| {{$isWikiEnabled := or (.Repository.UnitEnabled $.UnitTypeWiki) (.Repository.UnitEnabled $.UnitTypeExternalWiki)}} | {{$isWikiEnabled := or (.Repository.UnitEnabled $.UnitTypeWiki) (.Repository.UnitEnabled $.UnitTypeExternalWiki)}} | ||||
| <div class="inline field"> | <div class="inline field"> | ||||
| <label>{{.i18n.Tr "repo.wiki"}}</label> | <label>{{.i18n.Tr "repo.wiki"}}</label> | ||||
| @@ -50,16 +50,46 @@ | |||||
| {{end}} | {{end}} | ||||
| <li>{{svg "octicon-clock" 16}} {{.i18n.Tr "user.join_on"}} {{.Owner.CreatedUnix.FormatShort}}</li> | <li>{{svg "octicon-clock" 16}} {{.i18n.Tr "user.join_on"}} {{.Owner.CreatedUnix.FormatShort}}</li> | ||||
| {{if and .Orgs .HasOrgsVisible}} | {{if and .Orgs .HasOrgsVisible}} | ||||
| <li> | |||||
| <ul class="user-orgs"> | |||||
| <li style="border-bottom: none;padding-bottom: 0;"><div style="border-bottom: 1px solid #eaeaea;padding-top: 5px;padding-bottom:5px"> <b> 组织</b></div></li> | |||||
| <li style="padding-bottom: 0px;"> | |||||
| <!-- <ul class="user-orgs"> | |||||
| {{range .Orgs}} | {{range .Orgs}} | ||||
| {{if (or .Visibility.IsPublic (and ($.SignedUser) (or .Visibility.IsLimited (and (.IsUserPartOfOrg $.SignedUserID) .Visibility.IsPrivate) ($.IsAdmin))))}} | {{if (or .Visibility.IsPublic (and ($.SignedUser) (or .Visibility.IsLimited (and (.IsUserPartOfOrg $.SignedUserID) .Visibility.IsPrivate) ($.IsAdmin))))}} | ||||
| <li> | <li> | ||||
| <a href="{{.HomeLink}}"><img class="ui image poping up" src="{{.RelAvatarLink}}" data-content="{{.Name}}" data-position="top center" data-variation="tiny inverted"></a> | |||||
| <ul> | |||||
| <a href="{{.HomeLink}}"><img class="ui image poping up" src="{{.RelAvatarLink}}" data-content="{{.Name}}" data-position="top center" data-variation="tiny inverted"></a> | |||||
| <span>{{.Name}}</span> | |||||
| </ul> | |||||
| </li> | </li> | ||||
| {{end}} | {{end}} | ||||
| {{end}} | {{end}} | ||||
| </ul> | |||||
| </ul> --> | |||||
| {{range .Orgs}} | |||||
| <ul class="user-orgs"> | |||||
| {{if (or .Visibility.IsPublic (and ($.SignedUser) (or .Visibility.IsLimited (and (.IsUserPartOfOrg $.SignedUserID) .Visibility.IsPrivate) ($.IsAdmin))))}} | |||||
| <li class="infor" style="width: 15%;" > | |||||
| <a href="{{.HomeLink}}"><img class="ui image poping up" src="{{.RelAvatarLink}}" data-content="{{.Name}}" data-position="top center" data-variation="tiny inverted"></a> | |||||
| </li> | |||||
| <li class="infor" style="width: 35%;"> | |||||
| <a class="ui image poping up" style="color: #0366D6;overflow: hidden; white-space: nowrap; text-overflow: ellipsis;" href="{{.HomeLink}}" data-content="{{.Name}}" data-position="top center" data-variation="tiny inverted">{{.Name}}</a> | |||||
| </li> | |||||
| <li class="infor" style="width: 25%;"> | |||||
| <img style="width: 14px; height: 14px;border: none;" src="/img/member.svg" > | |||||
| <span style="color: rgba(0,0,0,.4);padding-left: 5px;">{{.NumMembers}}</span> | |||||
| </li> | |||||
| <li class="infor" style="width: 25%;"> | |||||
| <img style="width: 14px; height: 14px" src="/img/pro_num.svg" > | |||||
| <span style="color: rgba(0,0,0,.4);padding-left: 5px;">{{.NumRepos}}</span> | |||||
| </li> | |||||
| {{end}} | |||||
| </ul> | |||||
| {{end}} | |||||
| </li> | </li> | ||||
| {{end}} | {{end}} | ||||
| {{if and .IsSigned (ne .SignedUserName .Owner.Name)}} | {{if and .IsSigned (ne .SignedUserName .Owner.Name)}} | ||||
| @@ -83,15 +113,18 @@ | |||||
| </div> | </div> | ||||
| <div class="ui eleven wide column"> | <div class="ui eleven wide column"> | ||||
| <div class="ui secondary stackable pointing menu"> | <div class="ui secondary stackable pointing menu"> | ||||
| <a class='{{if and (ne .TabName "datasets") (ne .TabName "activity") (ne .TabName "following") (ne .TabName "followers") (ne .TabName "stars")}}active{{end}} item' href="{{.Owner.HomeLink}}"> | |||||
| <!-- <a class='{{if and (ne .TabName "datasets") (ne .TabName "activity") (ne .TabName "following") (ne .TabName "followers") (ne .TabName "stars")}}active{{end}} item' href="{{.Owner.HomeLink}}"> | |||||
| {{svg "octicon-repo" 16}} {{.i18n.Tr "user.repositories"}} | |||||
| </a> --> | |||||
| <a class='{{if eq .TabName "activity"}}active{{end}} item' href="{{.Owner.HomeLink}}?tab=activity"> | |||||
| {{svg "octicon-rss" 16}} {{.i18n.Tr "user.activity"}} | |||||
| </a> | |||||
| <a class='{{if eq .TabName "repository" }}active{{end}} item' href="{{.Owner.HomeLink}}?tab=repository"> | |||||
| {{svg "octicon-repo" 16}} {{.i18n.Tr "user.repositories"}} | {{svg "octicon-repo" 16}} {{.i18n.Tr "user.repositories"}} | ||||
| </a> | </a> | ||||
| <a class='{{if eq .TabName "datasets"}}active{{end}} item' href="{{.Owner.HomeLink}}?tab=datasets"> | <a class='{{if eq .TabName "datasets"}}active{{end}} item' href="{{.Owner.HomeLink}}?tab=datasets"> | ||||
| {{svg "octicon-inbox" 16}} {{.i18n.Tr "user.datasets"}} | {{svg "octicon-inbox" 16}} {{.i18n.Tr "user.datasets"}} | ||||
| </a> | </a> | ||||
| <a class='{{if eq .TabName "activity"}}active{{end}} item' href="{{.Owner.HomeLink}}?tab=activity"> | |||||
| {{svg "octicon-rss" 16}} {{.i18n.Tr "user.activity"}} | |||||
| </a> | |||||
| <a class='{{if eq .TabName "stars"}}active{{end}} item' href="{{.Owner.HomeLink}}?tab=stars"> | <a class='{{if eq .TabName "stars"}}active{{end}} item' href="{{.Owner.HomeLink}}?tab=stars"> | ||||
| {{svg "octicon-star" 16}} {{.i18n.Tr "user.starred"}} | {{svg "octicon-star" 16}} {{.i18n.Tr "user.starred"}} | ||||
| <div class="ui label">{{.Owner.NumStars}}</div> | <div class="ui label">{{.Owner.NumStars}}</div> | ||||
| @@ -144,3 +177,22 @@ | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| {{template "base/footer" .}} | {{template "base/footer" .}} | ||||
| <style> | |||||
| .infor{ | |||||
| margin: auto 0; | |||||
| } | |||||
| .user-orgs{ | |||||
| padding: 10px 0px; | |||||
| } | |||||
| .user-orgs li{ | |||||
| max-width: 50%; | |||||
| float: right; | |||||
| } | |||||
| .user.profile .ui.card .extra.content ul { | |||||
| padding: 5px 0; | |||||
| } | |||||
| </style> | |||||
| @@ -3,7 +3,7 @@ | |||||
| <el-tabs tab-position="left" v-model="activeName" style="height:100%" @tab-click="handleClick" > | <el-tabs tab-position="left" v-model="activeName" style="height:100%" @tab-click="handleClick" > | ||||
| <el-tab-pane label="概览" name="first" > | <el-tab-pane label="概览" name="first" > | ||||
| <span slot="label"> | <span slot="label"> | ||||
| <el-image style="width: 13px; height: 13px" src="/img/overview.png"> | |||||
| <el-image style="width: 13px; height: 13px" src="/img/overview_rgb.svg"> | |||||
| </el-image> | </el-image> | ||||
| 概览 | 概览 | ||||
| </span> | </span> | ||||
| @@ -13,14 +13,14 @@ | |||||
| <el-tab-pane label="项目分析" name="second" id="second" > | <el-tab-pane label="项目分析" name="second" id="second" > | ||||
| <ProAnalysis ref='ProAnalysis'id="pro" v-if="isRouterAlive"></ProAnalysis> | <ProAnalysis ref='ProAnalysis'id="pro" v-if="isRouterAlive"></ProAnalysis> | ||||
| <span slot="label"> | <span slot="label"> | ||||
| <el-image style="width: 13px; height: 13px" src="/img/pro_new.svg"> | |||||
| <el-image style="width: 13px; height: 13px" src="/img/pro_rgb.svg"> | |||||
| </el-image> | </el-image> | ||||
| 项目分析 | 项目分析 | ||||
| </span> | </span> | ||||
| </el-tab-pane> | </el-tab-pane> | ||||
| <el-tab-pane name="third" id='third' > | <el-tab-pane name="third" id='third' > | ||||
| <span slot='label'> | <span slot='label'> | ||||
| <el-image style="width: 13px; height: 13px" src="/img/name.png"> | |||||
| <el-image style="width: 13px; height: 13px" src="/img/user_rgb.svg"> | |||||
| </el-image> | </el-image> | ||||
| 用户分析 | 用户分析 | ||||
| </span> | </span> | ||||
| @@ -121,6 +121,14 @@ | |||||
| /deep/ .el-tabs__item { | /deep/ .el-tabs__item { | ||||
| padding: 0px 20px 0px 20px; | padding: 0px 20px 0px 20px; | ||||
| } | } | ||||
| /deep/ .el-tabs__item.is-active .el-image{ | |||||
| filter:none | |||||
| } | |||||
| /deep/ .el-tabs__item:hover .el-image{ | |||||
| filter:none | |||||
| } | |||||
| /deep/ .el-image{ | |||||
| filter:grayscale(100%) | |||||
| } | |||||
| </style> | </style> | ||||
| @@ -0,0 +1,520 @@ | |||||
| <template> | |||||
| <div> | |||||
| <div class="ui container" id="header"> | |||||
| <el-row style="margin-top:15px;"> | |||||
| <el-table | |||||
| ref="table" | |||||
| :data="tableData" | |||||
| style="min-width: 100%" | |||||
| row-key="ID" | |||||
| lazy | |||||
| :load="load" | |||||
| :tree-props="{children: 'Children', hasChildren: 'hasChildren'}" | |||||
| :header-cell-style="tableHeaderStyle" | |||||
| > | |||||
| <el-table-column | |||||
| prop="Name" | |||||
| label="模型名称" | |||||
| align="left" | |||||
| min-width="18%" | |||||
| > | |||||
| <template slot-scope="scope"> | |||||
| <div class="expand-icon" v-if="scope.row.hasChildren===false"> | |||||
| <i class="el-icon-arrow-right"></i> | |||||
| </div> | |||||
| <!-- <i class="el-icon-time"></i> --> | |||||
| <a class="text-over" :href="showinfoHref+scope.row.Name" :title="scope.row.Name">{{ scope.row.Name }}</a> | |||||
| </template> | |||||
| </el-table-column> | |||||
| <el-table-column | |||||
| prop="Version" | |||||
| label="版本" | |||||
| align="center" | |||||
| min-width="6.5%" | |||||
| > | |||||
| <template slot-scope="scope"> | |||||
| <span class="text-over" :title="scope.row.Version">{{ scope.row.Version}}</span> | |||||
| </template> | |||||
| </el-table-column> | |||||
| <el-table-column | |||||
| prop="VersionCount" | |||||
| label="版本数" | |||||
| align="center" | |||||
| min-width="7.5%" | |||||
| > | |||||
| <template slot-scope="scope"> | |||||
| <span class="text-over" :title="scope.row.VersionCount">{{ scope.row.VersionCount}}</span> | |||||
| </template> | |||||
| </el-table-column> | |||||
| <el-table-column | |||||
| prop="Size" | |||||
| label="模型大小" | |||||
| align="center" | |||||
| min-width="10.5%" | |||||
| > | |||||
| <template slot-scope="scope"> | |||||
| <span class="text-over">{{ renderSize(scope.row.Size)}}</span> | |||||
| </template> | |||||
| </el-table-column> | |||||
| <el-table-column | |||||
| prop="EngineName" | |||||
| label="AI引擎" | |||||
| align="center" | |||||
| min-width="8.5%" | |||||
| > | |||||
| <template slot-scope="scope"> | |||||
| <span class="text-over">{{ scope.row.EngineName}}</span> | |||||
| </template> | |||||
| </el-table-column> | |||||
| <el-table-column | |||||
| prop="ComputeResource" | |||||
| label="计算资源" | |||||
| align="center" | |||||
| min-width="10.5%" | |||||
| > | |||||
| <template slot-scope="scope"> | |||||
| <span class="text-over">{{ scope.row.ComputeResource}}</span> | |||||
| </template> | |||||
| </el-table-column> | |||||
| <el-table-column | |||||
| prop="CreatedUnix" | |||||
| label="创建时间" | |||||
| align="center" | |||||
| min-width="13.75%" | |||||
| > | |||||
| <template slot-scope="scope"> | |||||
| {{transTime(scope.row.CreatedUnix)}} | |||||
| </template> | |||||
| </el-table-column> | |||||
| <el-table-column | |||||
| prop="UserName" | |||||
| label="创建者" | |||||
| align="center" | |||||
| min-width="6.75%" | |||||
| > | |||||
| <template slot-scope="scope"> | |||||
| <a :href="!scope.row.UserName? '#':'/'+scope.row.UserName" :title="scope.row.UserName||defaultAvatarName"> | |||||
| <img class="ui avatar image" :src="scope.row.UserRelAvatarLink||defaultAvatar"> | |||||
| </a> | |||||
| </template> | |||||
| </el-table-column> | |||||
| <el-table-column label="操作" min-width="18%" align="center"> | |||||
| <template slot-scope="scope"> | |||||
| <div class="space-around"> | |||||
| <a :style="{visibility:!scope.row.Children ? 'visible':'hidden'}" :class="{'disabled':!scope.row.IsCanOper}" @click="showcreateVue(scope.row.Name,scope.row.Version,scope.row.Label)">创建新版本</a> | |||||
| <a :href="loadhref+scope.row.ID" :class="{'disabled':!scope.row.IsCanOper}">下载</a> | |||||
| <a :class="{'disabled':!scope.row.IsCanOper}" @click="deleteModel(scope.row.ID,scope.row.cName)">删除</a> | |||||
| </div> | |||||
| </template> | |||||
| </el-table-column> | |||||
| </el-table> | |||||
| </el-row> | |||||
| <div class="ui container" style="margin-top:50px;text-align:center"> | |||||
| <el-pagination | |||||
| background | |||||
| @size-change="handleSizeChange" | |||||
| @current-change="handleCurrentChange" | |||||
| :current-page="currentPage" | |||||
| :page-sizes="[5,10,15]" | |||||
| :page-size="pageSize" | |||||
| layout="total, sizes, prev, pager, next, jumper" | |||||
| :total="totalNum"> | |||||
| </el-pagination> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </template> | |||||
| <script> | |||||
| const {_AppSubUrl, _StaticUrlPrefix, csrf} = window.config; | |||||
| export default { | |||||
| components: { | |||||
| }, | |||||
| data() { | |||||
| return { | |||||
| currentPage:1, | |||||
| pageSize:10, | |||||
| totalNum:0, | |||||
| params:{page:0,pageSize:10}, | |||||
| tableData: [], | |||||
| url:'', | |||||
| isLoading:true, | |||||
| loadNodeMap:new Map(), | |||||
| submitId:{}, | |||||
| defaultAvatar:'/user/avatar/Ghost/-1', | |||||
| defaultAvatarName:'Ghost', | |||||
| data:'' | |||||
| }; | |||||
| }, | |||||
| methods: { | |||||
| load(tree, treeNode, resolve) { | |||||
| try{ | |||||
| this.loadNodeMap.set(tree.cName, {tree,treeNode,resolve}) | |||||
| this.$axios.get(this.url+'show_model_child_api',{params:{ | |||||
| name:tree.cName | |||||
| }}).then((res)=>{ | |||||
| let TrainTaskInfo | |||||
| let tableData | |||||
| tableData= res.data | |||||
| for(let i=0;i<tableData.length;i++){ | |||||
| TrainTaskInfo = JSON.parse(tableData[i].TrainTaskInfo) | |||||
| tableData[i].EngineName = TrainTaskInfo.EngineName.split('-')[0] | |||||
| tableData[i].ComputeResource = TrainTaskInfo.ComputeResource | |||||
| tableData[i].cName=tableData[i].Name | |||||
| tableData[i].Name='' | |||||
| tableData[i].VersionCount = '' | |||||
| tableData[i].Children = true | |||||
| } | |||||
| resolve(tableData||[]) | |||||
| }) | |||||
| } | |||||
| catch(e){ | |||||
| this.loading = false; | |||||
| } | |||||
| }, | |||||
| tableHeaderStyle({row,column,rowIndex,columnIndex}){ | |||||
| if(rowIndex===0){ | |||||
| return 'background:#f5f5f6;color:#606266' | |||||
| } | |||||
| }, | |||||
| handleSizeChange(val){ | |||||
| this.params.pageSize = val | |||||
| this.getModelList() | |||||
| }, | |||||
| handleCurrentChange(val){ | |||||
| this.params.page = val | |||||
| this.getModelList() | |||||
| }, | |||||
| showcreateVue(name,version,label){ | |||||
| $('.ui.modal.second') | |||||
| .modal({ | |||||
| centered: false, | |||||
| onShow:function(){ | |||||
| $('#model_header').text("创建模型新版本") | |||||
| $('input[name="Name"]').addClass('model_disabled') | |||||
| $('input[name="Name"]').attr('readonly','readonly') | |||||
| $('input[name="Version"]').addClass('model_disabled') | |||||
| $('.ui.dimmer').css({"background-color":"rgb(136, 136, 136,0.7)"}) | |||||
| $("#job-name").empty() | |||||
| $('#name').val(name) | |||||
| $('#label').val(label) | |||||
| let version_string = versionAdd(version) | |||||
| $('#version').val(version_string) | |||||
| loadTrainList() | |||||
| }, | |||||
| onHide:function(){ | |||||
| document.getElementById("formId").reset(); | |||||
| $('input[name="Name"]').removeClass('model_disabled') | |||||
| $('input[name="Name"]').removeAttr('readonly') | |||||
| $('#choice_model').dropdown('clear') | |||||
| $('#choice_version').dropdown('clear') | |||||
| $('.ui.dimmer').css({"background-color":""}) | |||||
| $('.ui.error.message').text() | |||||
| $('.ui.error.message').css('display','none') | |||||
| } | |||||
| }) | |||||
| .modal('show') | |||||
| }, | |||||
| check(){ | |||||
| let jobid = document.getElementById("JobId").value | |||||
| let versionname = document.getElementById("VersionName").value | |||||
| let name= document.getElementById("name").value | |||||
| let version= document.getElementById("version").value | |||||
| if(jobid==""){ | |||||
| $(".required.ten.wide.field").addClass("error") | |||||
| return false | |||||
| }else{ | |||||
| $(".required.ten.wide.field").removeClass("error") | |||||
| } | |||||
| if(versionname==""){ | |||||
| $(".required.six.widde.field").addClass("error") | |||||
| return false | |||||
| }else{ | |||||
| $(".required.six.widde.field").removeClass("error") | |||||
| } | |||||
| if(name==""){ | |||||
| $("#modelname").addClass("error") | |||||
| return false | |||||
| }else{ | |||||
| $("#modelname").removeClass("error") | |||||
| } | |||||
| if(versionname==""){ | |||||
| $("#verionname").addClass("error") | |||||
| return false | |||||
| }else{ | |||||
| $("#verionname").removeClass("error") | |||||
| } | |||||
| return true | |||||
| }, | |||||
| submit(){ | |||||
| let context = this | |||||
| let flag= this.check() | |||||
| if(flag){ | |||||
| let cName = $("input[name='Name']").val() | |||||
| let version = $("input[name='Version']").val() | |||||
| let data = $("#formId").serialize() | |||||
| $("#mask").css({"display":"block","z-index":"9999"}) | |||||
| $.ajax({ | |||||
| url:url_href, | |||||
| type:'POST', | |||||
| data:data, | |||||
| success:function(res){ | |||||
| // context.loadrefresh1(row) | |||||
| context.getModelList() | |||||
| $('.ui.modal.second').modal('hide') | |||||
| }, | |||||
| error: function(xhr){ | |||||
| // 隐藏 loading | |||||
| // 只有请求不正常(状态码不为200)才会执行 | |||||
| $('.ui.error.message').text(xhr.responseText) | |||||
| $('.ui.error.message').css('display','block') | |||||
| }, | |||||
| complete:function(xhr){ | |||||
| $("#mask").css({"display":"none","z-index":"1"}) | |||||
| } | |||||
| }) | |||||
| }else{ | |||||
| return false | |||||
| } | |||||
| }, | |||||
| loadrefresh(row){ | |||||
| const store = this.$refs.table.store | |||||
| if(!this.loadNodeMap.get(row.cName)){ | |||||
| const parent = store.states.data | |||||
| const index = parent.findIndex(child => child.ID == row.ID) | |||||
| parent.splice(index, 1) | |||||
| }else{ | |||||
| let {tree,treeNode,resolve} = this.loadNodeMap.get(row.cName) | |||||
| const keys = Object.keys(store.states.lazyTreeNodeMap); | |||||
| if(keys.includes(row.ID)){ | |||||
| this.getModelList() | |||||
| }else{ | |||||
| let parentRow = store.states.data.find(child => child.cName == row.cName); | |||||
| let childrenIndex = store.states.lazyTreeNodeMap[parentRow.ID].findIndex(child => child.ID == row.ID) | |||||
| parentRow.VersionCount = parentRow.VersionCount-1 | |||||
| const parent = store.states.lazyTreeNodeMap[parentRow.ID] | |||||
| if(parent.length===1){ | |||||
| this.getModelList() | |||||
| }else{ | |||||
| parent.splice(childrenIndex, 1); | |||||
| } | |||||
| } | |||||
| } | |||||
| }, | |||||
| deleteModel(id,name){ | |||||
| let row={cName:name,ID:id} | |||||
| let _this = this | |||||
| let flag=1 | |||||
| $('.ui.basic.modal.first') | |||||
| .modal({ | |||||
| onDeny: function() { | |||||
| flag = false | |||||
| }, | |||||
| onApprove: function() { | |||||
| _this.$axios.delete(_this.url+'delete_model',{ | |||||
| params:{ | |||||
| ID:id | |||||
| }}).then((res)=>{ | |||||
| _this.loadrefresh(row) | |||||
| // _this.getModelList() | |||||
| }) | |||||
| flag = true | |||||
| }, | |||||
| onHidden: function() { | |||||
| if (flag == false) { | |||||
| $('.alert').html('您已取消操作').removeClass('alert-success').addClass('alert-danger').show().delay(1500).fadeOut(); | |||||
| }else{ | |||||
| $('.alert').html('删除成功').removeClass('alert-danger').addClass('alert-success').show().delay(1500).fadeOut(); | |||||
| } | |||||
| } | |||||
| }) | |||||
| .modal('show') | |||||
| }, | |||||
| getModelList(){ | |||||
| try { | |||||
| this.$refs.table.store.states.lazyTreeNodeMap = {} | |||||
| this.$axios.get(location.href+'_api',{ | |||||
| params:this.params | |||||
| }).then((res)=>{ | |||||
| $(".ui.grid").removeAttr("style") | |||||
| $("#loadContainer").removeClass("loader") | |||||
| let TrainTaskInfo | |||||
| this.tableData = res.data.data | |||||
| for(let i=0;i<this.tableData.length;i++){ | |||||
| TrainTaskInfo = JSON.parse(this.tableData[i].TrainTaskInfo) | |||||
| this.tableData[i].cName=this.tableData[i].Name | |||||
| this.tableData[i].EngineName = TrainTaskInfo.EngineName.split('-')[0] | |||||
| this.tableData[i].ComputeResource = TrainTaskInfo.ComputeResource | |||||
| this.tableData[i].hasChildren = res.data.data[i].VersionCount===1 ? false : true | |||||
| } | |||||
| this.totalNum = res.data.count | |||||
| }) | |||||
| }catch (e) { | |||||
| console.log(e) | |||||
| } | |||||
| }, | |||||
| }, | |||||
| computed:{ | |||||
| loadhref(){ | |||||
| return this.url+'downloadall?ID=' | |||||
| }, | |||||
| showinfoHref(){ | |||||
| return this.url + 'show_model_info?name=' | |||||
| }, | |||||
| transTime(){ | |||||
| return function(time){ | |||||
| let date = new Date(time * 1000);//时间戳为10位需*1000,时间戳为13位的话不需乘1000 | |||||
| let Y = date.getFullYear() + '-'; | |||||
| let M = (date.getMonth()+1 < 10 ? '0'+(date.getMonth()+1):date.getMonth()+1) + '-'; | |||||
| let D = (date.getDate()< 10 ? '0'+date.getDate():date.getDate())+ ' '; | |||||
| let h = (date.getHours() < 10 ? '0'+date.getHours():date.getHours())+ ':'; | |||||
| let m = (date.getMinutes() < 10 ? '0'+date.getMinutes():date.getMinutes()) + ':'; | |||||
| let s = date.getSeconds() < 10 ? '0'+date.getSeconds():date.getSeconds(); | |||||
| return Y+M+D+h+m+s; | |||||
| } | |||||
| }, | |||||
| renderSize(){ | |||||
| return function(value){ | |||||
| if(null==value||value==''){ | |||||
| return "0 Bytes"; | |||||
| } | |||||
| var unitArr = new Array("Bytes","KB","MB","GB","TB","PB","EB","ZB","YB"); | |||||
| var index=0; | |||||
| var srcsize = parseFloat(value); | |||||
| index=Math.floor(Math.log(srcsize)/Math.log(1024)); | |||||
| var size =srcsize/Math.pow(1024,index); | |||||
| size=size.toFixed(2);//保留的小数位数 | |||||
| return size+unitArr[index]; | |||||
| } | |||||
| } | |||||
| }, | |||||
| mounted() { | |||||
| this.submitId = document.getElementById("submitId") | |||||
| this.getModelList() | |||||
| this.url = location.href.split('show_model')[0] | |||||
| this.submitId.addEventListener("click", this.submit) | |||||
| }, | |||||
| beforeDestroy() { // 实例销毁之前对点击事件进行解绑 | |||||
| this.submitId.removeEventListener('click', this.submit); | |||||
| } | |||||
| }; | |||||
| </script> | |||||
| <style scoped> | |||||
| /deep/ .el-pagination.is-background .el-pager li:not(.disabled).active { | |||||
| background-color: #5bb973; | |||||
| color: #FFF; | |||||
| } | |||||
| /deep/ .el-pagination.is-background .el-pager li.active { | |||||
| color: #fff; | |||||
| cursor: default; | |||||
| } | |||||
| /deep/ .el-pagination.is-background .el-pager li:hover { | |||||
| color: #5bb973; | |||||
| } | |||||
| /deep/ .el-pagination.is-background .el-pager li:not(.disabled):hover { | |||||
| color: #5bb973; | |||||
| } | |||||
| /deep/ .el-pagination.is-background .el-pager li:not(.disabled).active:hover { | |||||
| background-color: #5bb973; | |||||
| color: #FFF; | |||||
| } | |||||
| /deep/ .el-pager li.active { | |||||
| color: #08C0B9; | |||||
| cursor: default; | |||||
| } | |||||
| /deep/ .el-pagination .el-pager li:hover { | |||||
| color: #08C0B9; | |||||
| } | |||||
| /deep/ .el-pagination .el-pager li:not(.disabled):hover { | |||||
| color: #08C0B9; | |||||
| } | |||||
| .text-over{ | |||||
| overflow: hidden; | |||||
| text-overflow: ellipsis; | |||||
| vertical-align: middle; | |||||
| white-space: nowrap; | |||||
| } | |||||
| .el-icon-arrow-right{ | |||||
| font-family: element-icons!important; | |||||
| speak: none; | |||||
| font-style: normal; | |||||
| font-weight: 400; | |||||
| font-feature-settings: normal; | |||||
| font-variant: normal; | |||||
| text-transform: none; | |||||
| line-height: 1; | |||||
| vertical-align: middle; | |||||
| display: inline-block; | |||||
| -webkit-font-smoothing: antialiased; | |||||
| -moz-osx-font-smoothing: grayscale; | |||||
| border: 1px solid #D4D4D5; | |||||
| border-radius: 50%; | |||||
| color: #D4D4D5; | |||||
| margin-right: 4px; | |||||
| } | |||||
| .el-icon-arrow-right::before{ | |||||
| content: "\e6e0"; | |||||
| } | |||||
| .expand-icon{ | |||||
| display: inline-block; | |||||
| width: 20px; | |||||
| line-height: 20px; | |||||
| height: 20px; | |||||
| text-align: center; | |||||
| margin-right: 3px; | |||||
| font-size: 12px; | |||||
| } | |||||
| /deep/ .el-table_1_column_1.is-left .cell {padding-right: 0px !important;white-space: nowrap;} | |||||
| /deep/ .el-table__expand-icon .el-icon-arrow-right{ | |||||
| font-family: element-icons!important; | |||||
| speak: none; | |||||
| font-style: normal; | |||||
| font-weight: 400; | |||||
| font-feature-settings: normal; | |||||
| font-variant: normal; | |||||
| text-transform: none; | |||||
| line-height: 1; | |||||
| vertical-align: middle; | |||||
| display: inline-block; | |||||
| -webkit-font-smoothing: antialiased; | |||||
| -moz-osx-font-smoothing: grayscale; | |||||
| border: 1px solid #3291F8; | |||||
| border-radius: 50%; | |||||
| color: #3291F8; | |||||
| margin-right: 4px; | |||||
| } | |||||
| .space-around{ | |||||
| display: flex; | |||||
| justify-content: space-around; | |||||
| } | |||||
| .disabled { | |||||
| cursor: default; | |||||
| pointer-events: none; | |||||
| color: rgba(0,0,0,.6) !important; | |||||
| opacity: .45 !important; | |||||
| } | |||||
| </style> | |||||
| @@ -1085,6 +1085,12 @@ | |||||
| return data[0]+''+data[1]+''+data[2] | return data[0]+''+data[1]+''+data[2] | ||||
| } | } | ||||
| }, | }, | ||||
| goBack(){ | |||||
| if( $("#pro_detail").is(':visible') ){ | |||||
| document.getElementById("pro_main").style.display = "block"; | |||||
| document.getElementById("pro_detail").style.display = "none"; | |||||
| } | |||||
| }, | |||||
| }, | }, | ||||
| filters:{ | filters:{ | ||||
| @@ -1125,7 +1131,7 @@ | |||||
| return " <a href=\" mailto:" + value.email + "class=\"circular ui button\">" +value.user+ "</a>" | return " <a href=\" mailto:" + value.email + "class=\"circular ui button\">" +value.user+ "</a>" | ||||
| } | } | ||||
| }, | |||||
| }, | |||||
| }, | }, | ||||
| @@ -1140,6 +1146,10 @@ | |||||
| this.radarOpenI = this.$echarts.init(document.getElementById('radar_openi')) | this.radarOpenI = this.$echarts.init(document.getElementById('radar_openi')) | ||||
| this.echartsOITd = this.$echarts.init(document.getElementById('line_openi')) | this.echartsOITd = this.$echarts.init(document.getElementById('line_openi')) | ||||
| this.echartsSelectData = this.$echarts.init(document.getElementById('selectData')) | this.echartsSelectData = this.$echarts.init(document.getElementById('selectData')) | ||||
| if (window.history && window.history.pushState) { | |||||
| history.pushState(null, null, document.URL); | |||||
| window.addEventListener('popstate', this.goBack, false); | |||||
| } | |||||
| // window.onresize=function(){ | // window.onresize=function(){ | ||||
| // this.radarOpenI.resize(); | // this.radarOpenI.resize(); | ||||
| // this.echartsOITd.resize(); | // this.echartsOITd.resize(); | ||||
| @@ -27,10 +27,10 @@ | |||||
| </span> | </span> | ||||
| <span style="float:right; margin-right: 20px;" > | <span style="float:right; margin-right: 20px;" > | ||||
| <a style="display:inline-block;margin-left: 20px; " id = 'download'> | <a style="display:inline-block;margin-left: 20px; " id = 'download'> | ||||
| <a class="el-icon-download" v-if="tableData!=''" :href= "'../tool/query_user_static_page/?startDate='+this.params.startDate+'&endDate='+this.params.endDate+'&IsReturnFile=true'+'&userName='+this.params.userName" ></a> | |||||
| <a class="el-icon-download" v-if="tableData!=''" :href= "'../api/v1/query_user_static_page/?startDate='+this.params.startDate+'&endDate='+this.params.endDate+'&IsReturnFile=true'+'&userName='+this.params.userName" ></a> | |||||
| <i class="el-icon-download" v-else="tableData=''" href="#" style="color:rgba(187, 187, 187, 100);" @click='popMark()'></i> | <i class="el-icon-download" v-else="tableData=''" href="#" style="color:rgba(187, 187, 187, 100);" @click='popMark()'></i> | ||||
| <span > | <span > | ||||
| <a v-if="tableData!=''" :href= "'../tool/query_user_static_page/?startDate='+this.params.startDate+'&endDate='+this.params.endDate+'&IsReturnFile=true'+'&userName='+this.params.userName" >下载报告</a> | |||||
| <a v-if="tableData!=''" :href= "'../api/v1/query_user_static_page/?startDate='+this.params.startDate+'&endDate='+this.params.endDate+'&IsReturnFile=true'+'&userName='+this.params.userName" >下载报告</a> | |||||
| <a v-else="tableData=''" href= "#" style="color:rgba(187, 187, 187, 100);" @click='popMark()'>下载报告</a> | <a v-else="tableData=''" href= "#" style="color:rgba(187, 187, 187, 100);" @click='popMark()'>下载报告</a> | ||||
| </span> | </span> | ||||
| </a> | </a> | ||||
| @@ -335,7 +335,7 @@ | |||||
| } | } | ||||
| }; | }; | ||||
| this.$axios.get('../tool/query_user_static_page',{ | |||||
| this.$axios.get('../api/v1/query_user_static_page',{ | |||||
| params:this.params | params:this.params | ||||
| }).then((res)=>{ | }).then((res)=>{ | ||||
| this.tableData = res.data.data | this.tableData = res.data.data | ||||
| @@ -39,6 +39,7 @@ import Images from './components/Images.vue'; | |||||
| import EditTopics from './components/EditTopics.vue'; | import EditTopics from './components/EditTopics.vue'; | ||||
| import DataAnalysis from './components/DataAnalysis.vue' | import DataAnalysis from './components/DataAnalysis.vue' | ||||
| import Contributors from './components/Contributors.vue' | import Contributors from './components/Contributors.vue' | ||||
| import Model from './components/Model.vue'; | |||||
| Vue.use(ElementUI); | Vue.use(ElementUI); | ||||
| Vue.prototype.$axios = axios; | Vue.prototype.$axios = axios; | ||||
| @@ -2916,11 +2917,12 @@ $(document).ready(async () => { | |||||
| initVueEditTopic(); | initVueEditTopic(); | ||||
| initVueContributors(); | initVueContributors(); | ||||
| initVueImages(); | initVueImages(); | ||||
| initVueModel(); | |||||
| initVueDataAnalysis(); | initVueDataAnalysis(); | ||||
| initTeamSettings(); | initTeamSettings(); | ||||
| initCtrlEnterSubmit(); | initCtrlEnterSubmit(); | ||||
| initNavbarContentToggle(); | initNavbarContentToggle(); | ||||
| // initTopicbar(); | |||||
| // initTopicbar();vim | |||||
| // closeTopicbar(); | // closeTopicbar(); | ||||
| initU2FAuth(); | initU2FAuth(); | ||||
| initU2FRegister(); | initU2FRegister(); | ||||
| @@ -2933,6 +2935,7 @@ $(document).ready(async () => { | |||||
| initNotificationsTable(); | initNotificationsTable(); | ||||
| initNotificationCount(); | initNotificationCount(); | ||||
| initTribute(); | initTribute(); | ||||
| initDropDown(); | |||||
| // Repo clone url. | // Repo clone url. | ||||
| if ($('#repo-clone-url').length > 0) { | if ($('#repo-clone-url').length > 0) { | ||||
| @@ -3646,7 +3649,7 @@ function initVueContributors() { | |||||
| function initVueImages() { | function initVueImages() { | ||||
| const el = document.getElementById('images'); | const el = document.getElementById('images'); | ||||
| console.log("el",el) | |||||
| if (!el) { | if (!el) { | ||||
| return; | return; | ||||
| @@ -3658,6 +3661,20 @@ function initVueImages() { | |||||
| render: h => h(Images) | render: h => h(Images) | ||||
| }); | }); | ||||
| } | } | ||||
| function initVueModel() { | |||||
| const el = document.getElementById('model_list'); | |||||
| if (!el) { | |||||
| return; | |||||
| } | |||||
| new Vue({ | |||||
| el: el, | |||||
| render: h => h(Model) | |||||
| }); | |||||
| } | |||||
| function initVueDataAnalysis() { | function initVueDataAnalysis() { | ||||
| const el = document.getElementById('data_analysis'); | const el = document.getElementById('data_analysis'); | ||||
| console.log("el",el) | console.log("el",el) | ||||
| @@ -3728,6 +3745,7 @@ function initFilterBranchTagDropdown(selector) { | |||||
| }); | }); | ||||
| }); | }); | ||||
| $data.remove(); | $data.remove(); | ||||
| console.log("-this",this) | |||||
| new Vue({ | new Vue({ | ||||
| delimiters: ['${', '}'], | delimiters: ['${', '}'], | ||||
| el: this, | el: this, | ||||
| @@ -4100,3 +4118,22 @@ $.get(`${window.config.StaticUrlPrefix}/img/svg/icons.svg`, (data) => { | |||||
| div.innerHTML = new XMLSerializer().serializeToString(data.documentElement); | div.innerHTML = new XMLSerializer().serializeToString(data.documentElement); | ||||
| document.body.insertBefore(div, document.body.childNodes[0]); | document.body.insertBefore(div, document.body.childNodes[0]); | ||||
| }); | }); | ||||
| function initDropDown() { | |||||
| $("#dropdown_PageHome").dropdown({ | |||||
| on:'hover' ,//鼠标悬浮显示,默认值是click | |||||
| }); | |||||
| $("#dropdown_explore").dropdown({ | |||||
| on:'hover' ,//鼠标悬浮显示,默认值是click | |||||
| }); | |||||
| } | |||||
| //云脑提示 | |||||
| $('.question.circle.icon').hover(function(){ | |||||
| $(this).popup('show') | |||||
| $('.ui.popup.mini.top.center').css({"border-color":'rgba(50, 145, 248, 100)',"color":"rgba(3, 102, 214, 100)","border-radius":"5px","border-shadow":"none"}) | |||||
| }); | |||||
| //云脑详情页面跳转回上一个页面 | |||||
| $(".section.backTodeBug").attr("href",localStorage.getItem('all')) | |||||
| //新建调试取消跳转 | |||||
| $(".ui.button.cancel").attr("href",localStorage.getItem('all')) | |||||
| @@ -2,6 +2,7 @@ | |||||
| display: inline-block; | display: inline-block; | ||||
| vertical-align: text-top; | vertical-align: text-top; | ||||
| fill: currentColor; | fill: currentColor; | ||||
| margin-right: 5px; | |||||
| .middle & { | .middle & { | ||||
| vertical-align: middle; | vertical-align: middle; | ||||
| @@ -292,7 +292,8 @@ footer .column{margin-bottom:0!important; padding-bottom:0!important;} | |||||
| } | } | ||||
| .hover_active{ | .hover_active{ | ||||
| height: 100% !important; | |||||
| margin-top: 1px !important; | |||||
| } | } | ||||
| .dropdown-menu:hover .dropdown-content { | .dropdown-menu:hover .dropdown-content { | ||||
| display: block; | display: block; | ||||
| @@ -335,4 +336,252 @@ display: block; | |||||
| margin-left: 4px !important; | margin-left: 4px !important; | ||||
| color: #3291F8; | color: #3291F8; | ||||
| } | |||||
| } | |||||
| //缺省页 | |||||
| .bgtask-none{ | |||||
| background: #fff !important; | |||||
| border: 0 !important; | |||||
| box-shadow: none !important; | |||||
| padding-bottom: 0 !important; | |||||
| padding-top: 2em !important; | |||||
| } | |||||
| .bgtask-header-pic { | |||||
| height: 80px; | |||||
| text-align: center; | |||||
| background: url(//ai-studio-static-online.cdn.bcebos.com/aistudio/dist/1638363279337/images/search_empty.png) top no-repeat; | |||||
| background-size: 80px 80px; | |||||
| } | |||||
| .bgtask-content{ | |||||
| margin: 2rem auto 0; | |||||
| /* width: 500px; */ | |||||
| text-align: left; | |||||
| } | |||||
| .bgtask-content-txt { | |||||
| font-size: 14px; | |||||
| color: #a6a6a6; | |||||
| line-height: 22px; | |||||
| margin-bottom: 4px; | |||||
| } | |||||
| .bgtask-content-header { | |||||
| text-align: center; | |||||
| color: #3F3F40; | |||||
| font-size: 18px; | |||||
| margin-bottom: 1rem; | |||||
| } | |||||
| .selectcloudbrain .active.item{ | |||||
| color: #0087f5 !important; | |||||
| border: 1px solid #0087f5; | |||||
| margin: -1px; | |||||
| background: #FFF !important; | |||||
| } | |||||
| #deletemodel { | |||||
| width: 100%; | |||||
| height: 100%; | |||||
| } | |||||
| /* 弹窗 */ | |||||
| #mask { | |||||
| position: fixed; | |||||
| top: 0px; | |||||
| left: 0px; | |||||
| right: 0px; | |||||
| bottom: 0px; | |||||
| filter: alpha(opacity=60); | |||||
| background-color: #777; | |||||
| z-index: 1000; | |||||
| display: none; | |||||
| opacity: 0.8; | |||||
| -moz-opacity: 0.5; | |||||
| padding-top: 100px; | |||||
| color: #000000 | |||||
| } | |||||
| #loadingPage { | |||||
| margin: 200px auto; | |||||
| width: 50px; | |||||
| height: 40px; | |||||
| text-align: center; | |||||
| font-size: 10px; | |||||
| display: block; | |||||
| } | |||||
| #loadingPage>div { | |||||
| background-color: green; | |||||
| height: 100%; | |||||
| width: 6px; | |||||
| display: inline-block; | |||||
| -webkit-animation: sk-stretchdelay 1.2s infinite ease-in-out; | |||||
| animation: sk-stretchdelay 1.2s infinite ease-in-out; | |||||
| } | |||||
| #loadingPage .rect2 { | |||||
| -webkit-animation-delay: -1.1s; | |||||
| animation-delay: -1.1s; | |||||
| } | |||||
| #loadingPage .rect3 { | |||||
| -webkit-animation-delay: -1.0s; | |||||
| animation-delay: -1.0s; | |||||
| } | |||||
| #loadingPage .rect4 { | |||||
| -webkit-animation-delay: -0.9s; | |||||
| animation-delay: -0.9s; | |||||
| } | |||||
| #loadingPage .rect5 { | |||||
| -webkit-animation-delay: -0.8s; | |||||
| animation-delay: -0.8s; | |||||
| } | |||||
| @-webkit-keyframes sk-stretchdelay { | |||||
| 0%, | |||||
| 40%, | |||||
| 100% { | |||||
| -webkit-transform: scaleY(0.4) | |||||
| } | |||||
| 20% { | |||||
| -webkit-transform: scaleY(1.0) | |||||
| } | |||||
| } | |||||
| @keyframes sk-stretchdelay { | |||||
| 0%, | |||||
| 40%, | |||||
| 100% { | |||||
| transform: scaleY(0.4); | |||||
| -webkit-transform: scaleY(0.4); | |||||
| } | |||||
| 20% { | |||||
| transform: scaleY(1.0); | |||||
| -webkit-transform: scaleY(1.0); | |||||
| } | |||||
| } | |||||
| /* 消息框 */ | |||||
| .alert { | |||||
| display: none; | |||||
| position: fixed; | |||||
| width: 100%; | |||||
| z-index: 1001; | |||||
| padding: 15px; | |||||
| border: 1px solid transparent; | |||||
| border-radius: 4px; | |||||
| text-align: center; | |||||
| font-weight: bold; | |||||
| } | |||||
| .alert-success { | |||||
| color: #3c763d; | |||||
| background-color: #dff0d8; | |||||
| border-color: #d6e9c6; | |||||
| } | |||||
| .alert-info { | |||||
| color: #31708f; | |||||
| background-color: #d9edf7; | |||||
| border-color: #bce8f1; | |||||
| } | |||||
| .alert-warning { | |||||
| color: #8a6d3b; | |||||
| background-color: #fcf8e3; | |||||
| border-color: #faebcc; | |||||
| } | |||||
| .alert-danger { | |||||
| color: #a94442; | |||||
| background-color: #f2dede; | |||||
| border-color: #ebccd1; | |||||
| } | |||||
| .pusher { | |||||
| width: calc(100% - 260px); | |||||
| box-sizing: border-box; | |||||
| } | |||||
| /* 弹窗 (background) */ | |||||
| #imageModal { | |||||
| display: none; | |||||
| position: fixed; | |||||
| z-index: 1; | |||||
| left: 0; | |||||
| top: 0; | |||||
| width: 100%; | |||||
| height: 100%; | |||||
| overflow: auto; | |||||
| background-color: rgb(0, 0, 0); | |||||
| background-color: rgba(0, 0, 0, 0.4); | |||||
| } | |||||
| /* 弹窗内容 */ | |||||
| .modal-content { | |||||
| background-color: #fefefe; | |||||
| margin: 15% auto; | |||||
| padding: 20px; | |||||
| border: 1px solid #888; | |||||
| width: 30%; | |||||
| } | |||||
| /* 关闭按钮 */ | |||||
| .close { | |||||
| color: #aaa; | |||||
| float: right; | |||||
| font-size: 28px; | |||||
| font-weight: bold; | |||||
| } | |||||
| .close:hover, | |||||
| .close:focus { | |||||
| color: black; | |||||
| text-decoration: none; | |||||
| cursor: pointer; | |||||
| } | |||||
| .dis { | |||||
| margin-bottom: 20px; | |||||
| } | |||||
| .disabled { | |||||
| cursor: pointer; | |||||
| pointer-events: none; | |||||
| } | |||||
| .left2{ | |||||
| margin-left: -2px !important; | |||||
| } | |||||
| .width70{ | |||||
| width: 70% !important; | |||||
| } | |||||
| .width83{ | |||||
| width: 83% !important; | |||||
| } | |||||
| .content-padding{ | |||||
| padding: 40px !important; | |||||
| } | |||||
| .model_disabled{ | |||||
| background-color: rgba(245, 245, 246, 100) !important; | |||||
| color: rgba(136, 136, 136, 100) !important; | |||||
| } | |||||
| .edge{ | |||||
| margin-left:0 !important; | |||||
| margin-right: 0 !important; | |||||
| padding-left:0 !important; | |||||
| padding-right:0 !important; | |||||
| } | |||||
| .lfpd { | |||||
| padding-left:0 !important; | |||||
| padding-right: 0 !important; | |||||
| } | |||||
| .mglf{ | |||||
| margin-left:0.5em !important; | |||||
| } | |||||
| .tooltips{ | |||||
| display: inline-block; | |||||
| margin-left: 5.5rem; | |||||
| font-size: 12px; | |||||
| margin-top: 0.7rem; | |||||
| color: #888888; | |||||
| } | |||||