@@ -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,203 @@ | |||||
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:"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:"NULL"` | |||||
CodeBranch string `xorm:"varchar(400) NULL"` | |||||
CodeCommitID string `xorm:"NULL"` | |||||
UserId int64 `xorm:"NOT NULL"` | |||||
UserName string `xorm:"NULL"` | |||||
UserRelAvatarLink string `xorm:"NULL"` | |||||
TrainTaskInfo string `xorm:"text NULL"` | |||||
CreatedUnix timeutil.TimeStamp `xorm:"created"` | |||||
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX 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("version 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) | |||||
} | |||||
sess.Close() | |||||
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,48 @@ 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"}, | |||||
) | |||||
sess.OrderBy("job_id DESC") | |||||
cloudbrains := make([]*CloudbrainInfo, 0) | |||||
if err := sess.Distinct("job_id,job_name").Table(&Cloudbrain{}).Where(cond). | |||||
Find(&cloudbrains); err != nil { | |||||
return nil, 0, fmt.Errorf("Find: %v", err) | |||||
} | |||||
return cloudbrains, int(len(cloudbrains)), 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 +1075,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 | ||||
} | } | ||||
@@ -1127,3 +1170,20 @@ func GetCloudBrainUnStoppedJob() ([]*Cloudbrain, error) { | |||||
Limit(100). | Limit(100). | ||||
Find(&cloudbrains) | Find(&cloudbrains) | ||||
} | } | ||||
func GetCloudbrainCountByUserID(userID int64) (int, error) { | |||||
count, err := x.In("status", JobWaiting, JobRunning).And("job_type = ? and user_id = ? and type = ?", JobTypeDebug, userID, TypeCloudBrainOne).Count(new(Cloudbrain)) | |||||
return int(count), err | |||||
} | |||||
func GetCloudbrainNotebookCountByUserID(userID int64) (int, error) { | |||||
count, err := x.In("status", ModelArtsCreateQueue, ModelArtsCreating, ModelArtsStarting, ModelArtsReadyToStart, ModelArtsResizing, ModelArtsStartQueuing, ModelArtsRunning, ModelArtsRestarting). | |||||
And("job_type = ? and user_id = ? and type = ?", JobTypeDebug, userID, TypeCloudBrainTwo).Count(new(Cloudbrain)) | |||||
return int(count), err | |||||
} | |||||
func GetCloudbrainTrainJobCountByUserID(userID int64) (int, error) { | |||||
count, err := x.In("status", ModelArtsTrainJobInit, ModelArtsTrainJobImageCreating, ModelArtsTrainJobSubmitTrying, ModelArtsTrainJobWaiting, ModelArtsTrainJobRunning, ModelArtsTrainJobScaling, ModelArtsTrainJobCheckInit, ModelArtsTrainJobCheckRunning, ModelArtsTrainJobCheckRunningCompleted). | |||||
And("job_type = ? and user_id = ? and type = ?", JobTypeTrain, userID, TypeCloudBrainTwo).Count(new(Cloudbrain)) | |||||
return int(count), err | |||||
} |
@@ -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, | ||||
@@ -1114,6 +1114,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, | ||||
@@ -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,7 +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"` //运营人员 | |||||
IsOperator bool `xorm:"NOT NULL DEFAULT false"` //运营人员 | |||||
// Avatar | // Avatar | ||||
Avatar string `xorm:"VARCHAR(2048) NOT NULL"` | Avatar string `xorm:"VARCHAR(2048) NOT NULL"` | ||||
@@ -929,8 +929,17 @@ var ( | |||||
"template", | "template", | ||||
"user", | "user", | ||||
"vendor", | "vendor", | ||||
} | |||||
reservedUserPatterns = []string{"*.keys", "*.gpg"} | |||||
"dashbord", | |||||
"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 | ||||
@@ -1552,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)) | ||||
@@ -1572,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) | ||||
@@ -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,9 +1,10 @@ | |||||
package cloudbrain | package cloudbrain | ||||
import ( | import ( | ||||
"code.gitea.io/gitea/modules/setting" | |||||
"errors" | "errors" | ||||
"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" | ||||
"code.gitea.io/gitea/modules/log" | "code.gitea.io/gitea/modules/log" | ||||
@@ -16,7 +17,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 +29,72 @@ var ( | |||||
ResourceSpecs *models.ResourceSpecs | ResourceSpecs *models.ResourceSpecs | ||||
) | ) | ||||
func isAdminOrOwnerOrJobCreater(ctx *context.Context, job *models.Cloudbrain, err error) bool { | |||||
if err != nil { | |||||
return ctx.IsUserRepoOwner() || ctx.IsUserSiteAdmin() | |||||
} else { | |||||
return ctx.IsUserRepoOwner() || ctx.IsUserSiteAdmin() || ctx.User.ID == job.UserID | |||||
} | |||||
} | |||||
func CanDeleteDebugJob(ctx *context.Context, job *models.Cloudbrain) bool { | |||||
if job.Status != string(models.JobStopped) && job.Status != string(models.JobFailed) && job.Status != string(models.ModelArtsStartFailed) && job.Status != string(models.ModelArtsCreateFailed) { | |||||
return false | |||||
} | |||||
return isAdminOrOwnerOrJobCreater(ctx, job, nil) | |||||
} | |||||
func CanDeleteTrainJob(ctx *context.Context, job *models.Cloudbrain) bool { | |||||
return isAdminOrOwnerOrJobCreater(ctx, job, nil) | |||||
} | |||||
func CanCreateOrDebugJob(ctx *context.Context) bool { | |||||
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 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 + "/" + | ||||
@@ -524,7 +524,7 @@ func RepoAssignment() macaron.Handler { | |||||
} | } | ||||
ctx.Data["Tags"] = tags | ctx.Data["Tags"] = tags | ||||
brs, err := ctx.Repo.GitRepo.GetBranches() | |||||
brs, _, err := ctx.Repo.GitRepo.GetBranches(0, 0) | |||||
if err != nil { | if err != nil { | ||||
ctx.ServerError("GetBranches", err) | ctx.ServerError("GetBranches", err) | ||||
return | return | ||||
@@ -712,7 +712,7 @@ func RepoRefByType(refType RepoRefType) macaron.Handler { | |||||
refName = ctx.Repo.Repository.DefaultBranch | refName = ctx.Repo.Repository.DefaultBranch | ||||
ctx.Repo.BranchName = refName | ctx.Repo.BranchName = refName | ||||
if !ctx.Repo.GitRepo.IsBranchExist(refName) { | if !ctx.Repo.GitRepo.IsBranchExist(refName) { | ||||
brs, err := ctx.Repo.GitRepo.GetBranches() | |||||
brs, _, err := ctx.Repo.GitRepo.GetBranches(0, 0) | |||||
if err != nil { | if err != nil { | ||||
ctx.ServerError("GetBranches", err) | ctx.ServerError("GetBranches", err) | ||||
return | return | ||||
@@ -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 | |||||
} | } | ||||
} | } |
@@ -6,7 +6,9 @@ | |||||
package git | package git | ||||
import ( | import ( | ||||
"bufio" | |||||
"fmt" | "fmt" | ||||
"io" | |||||
"strings" | "strings" | ||||
"github.com/go-git/go-git/v5/plumbing" | "github.com/go-git/go-git/v5/plumbing" | ||||
@@ -74,25 +76,6 @@ func (repo *Repository) SetDefaultBranch(name string) error { | |||||
return err | return err | ||||
} | } | ||||
// GetBranches returns all branches of the repository. | |||||
func (repo *Repository) GetBranches() ([]string, error) { | |||||
var branchNames []string | |||||
branches, err := repo.gogitRepo.Branches() | |||||
if err != nil { | |||||
return nil, err | |||||
} | |||||
_ = branches.ForEach(func(branch *plumbing.Reference) error { | |||||
branchNames = append(branchNames, strings.TrimPrefix(branch.Name().String(), BranchPrefix)) | |||||
return nil | |||||
}) | |||||
// TODO: Sort? | |||||
return branchNames, nil | |||||
} | |||||
// GetBranch returns a branch by it's name | // GetBranch returns a branch by it's name | ||||
func (repo *Repository) GetBranch(branch string) (*Branch, error) { | func (repo *Repository) GetBranch(branch string) (*Branch, error) { | ||||
if !repo.IsBranchExist(branch) { | if !repo.IsBranchExist(branch) { | ||||
@@ -106,16 +89,16 @@ func (repo *Repository) GetBranch(branch string) (*Branch, error) { | |||||
} | } | ||||
// GetBranchesByPath returns a branch by it's path | // GetBranchesByPath returns a branch by it's path | ||||
func GetBranchesByPath(path string) ([]*Branch, error) { | |||||
func GetBranchesByPath(path string, skip, limit int) ([]*Branch, int, error) { | |||||
gitRepo, err := OpenRepository(path) | gitRepo, err := OpenRepository(path) | ||||
if err != nil { | if err != nil { | ||||
return nil, err | |||||
return nil, 0, err | |||||
} | } | ||||
defer gitRepo.Close() | defer gitRepo.Close() | ||||
brs, err := gitRepo.GetBranches() | |||||
brs, countAll, err := gitRepo.GetBranches(skip, limit) | |||||
if err != nil { | if err != nil { | ||||
return nil, err | |||||
return nil, 0, err | |||||
} | } | ||||
branches := make([]*Branch, len(brs)) | branches := make([]*Branch, len(brs)) | ||||
@@ -127,7 +110,7 @@ func GetBranchesByPath(path string) ([]*Branch, error) { | |||||
} | } | ||||
} | } | ||||
return branches, nil | |||||
return branches, countAll, nil | |||||
} | } | ||||
// DeleteBranchOptions Option(s) for delete branch | // DeleteBranchOptions Option(s) for delete branch | ||||
@@ -183,3 +166,91 @@ func (repo *Repository) RemoveRemote(name string) error { | |||||
func (branch *Branch) GetCommit() (*Commit, error) { | func (branch *Branch) GetCommit() (*Commit, error) { | ||||
return branch.gitRepo.GetBranchCommit(branch.Name) | return branch.gitRepo.GetBranchCommit(branch.Name) | ||||
} | } | ||||
// GetBranches returns branches from the repository, skipping skip initial branches and | |||||
// returning at most limit branches, or all branches if limit is 0. | |||||
func (repo *Repository) GetBranches(skip, limit int) ([]string, int, error) { | |||||
return callShowRef(repo.Path, BranchPrefix, "--heads", skip, limit) | |||||
} | |||||
// callShowRef return refs, if limit = 0 it will not limit | |||||
func callShowRef(repoPath, prefix, arg string, skip, limit int) (branchNames []string, countAll int, err error) { | |||||
stdoutReader, stdoutWriter := io.Pipe() | |||||
defer func() { | |||||
_ = stdoutReader.Close() | |||||
_ = stdoutWriter.Close() | |||||
}() | |||||
go func() { | |||||
stderrBuilder := &strings.Builder{} | |||||
err := NewCommand("show-ref", arg).RunInDirPipeline(repoPath, stdoutWriter, stderrBuilder) | |||||
if err != nil { | |||||
if stderrBuilder.Len() == 0 { | |||||
_ = stdoutWriter.Close() | |||||
return | |||||
} | |||||
_ = stdoutWriter.CloseWithError(ConcatenateError(err, stderrBuilder.String())) | |||||
} else { | |||||
_ = stdoutWriter.Close() | |||||
} | |||||
}() | |||||
i := 0 | |||||
bufReader := bufio.NewReader(stdoutReader) | |||||
for i < skip { | |||||
_, isPrefix, err := bufReader.ReadLine() | |||||
if err == io.EOF { | |||||
return branchNames, i, nil | |||||
} | |||||
if err != nil { | |||||
return nil, 0, err | |||||
} | |||||
if !isPrefix { | |||||
i++ | |||||
} | |||||
} | |||||
for limit == 0 || i < skip+limit { | |||||
// The output of show-ref is simply a list: | |||||
// <sha> SP <ref> LF | |||||
_, err := bufReader.ReadSlice(' ') | |||||
for err == bufio.ErrBufferFull { | |||||
// This shouldn't happen but we'll tolerate it for the sake of peace | |||||
_, err = bufReader.ReadSlice(' ') | |||||
} | |||||
if err == io.EOF { | |||||
return branchNames, i, nil | |||||
} | |||||
if err != nil { | |||||
return nil, 0, err | |||||
} | |||||
branchName, err := bufReader.ReadString('\n') | |||||
if err == io.EOF { | |||||
// This shouldn't happen... but we'll tolerate it for the sake of peace | |||||
return branchNames, i, nil | |||||
} | |||||
if err != nil { | |||||
return nil, i, err | |||||
} | |||||
branchName = strings.TrimPrefix(branchName, prefix) | |||||
if len(branchName) > 0 { | |||||
branchName = branchName[:len(branchName)-1] | |||||
} | |||||
branchNames = append(branchNames, branchName) | |||||
i++ | |||||
} | |||||
// count all refs | |||||
for limit != 0 { | |||||
_, isPrefix, err := bufReader.ReadLine() | |||||
if err == io.EOF { | |||||
return branchNames, i, nil | |||||
} | |||||
if err != nil { | |||||
return nil, 0, err | |||||
} | |||||
if !isPrefix { | |||||
i++ | |||||
} | |||||
} | |||||
return branchNames, i, nil | |||||
} |
@@ -10,7 +10,6 @@ import ( | |||||
"strings" | "strings" | ||||
"github.com/go-git/go-git/v5/plumbing" | "github.com/go-git/go-git/v5/plumbing" | ||||
"github.com/mcuadros/go-version" | |||||
) | ) | ||||
// TagPrefix tags prefix path on the repository | // TagPrefix tags prefix path on the repository | ||||
@@ -225,29 +224,35 @@ func (repo *Repository) GetTagInfos(page, pageSize int) ([]*Tag, error) { | |||||
return tags, nil | return tags, nil | ||||
} | } | ||||
// GetTags returns all tags of the repository. | |||||
func (repo *Repository) GetTags() ([]string, error) { | |||||
var tagNames []string | |||||
tags, err := repo.gogitRepo.Tags() | |||||
if err != nil { | |||||
return nil, err | |||||
} | |||||
//// GetTags returns all tags of the repository. | |||||
//func (repo *Repository) GetTags() ([]string, error) { | |||||
// var tagNames []string | |||||
// | |||||
// tags, err := repo.gogitRepo.Tags() | |||||
// if err != nil { | |||||
// return nil, err | |||||
// } | |||||
// | |||||
// _ = tags.ForEach(func(tag *plumbing.Reference) error { | |||||
// tagNames = append(tagNames, strings.TrimPrefix(tag.Name().String(), TagPrefix)) | |||||
// return nil | |||||
// }) | |||||
// | |||||
// version.Sort(tagNames) | |||||
// | |||||
// // Reverse order | |||||
// for i := 0; i < len(tagNames)/2; i++ { | |||||
// j := len(tagNames) - i - 1 | |||||
// tagNames[i], tagNames[j] = tagNames[j], tagNames[i] | |||||
// } | |||||
// | |||||
// return tagNames, nil | |||||
//} | |||||
_ = tags.ForEach(func(tag *plumbing.Reference) error { | |||||
tagNames = append(tagNames, strings.TrimPrefix(tag.Name().String(), TagPrefix)) | |||||
return nil | |||||
}) | |||||
version.Sort(tagNames) | |||||
// Reverse order | |||||
for i := 0; i < len(tagNames)/2; i++ { | |||||
j := len(tagNames) - i - 1 | |||||
tagNames[i], tagNames[j] = tagNames[j], tagNames[i] | |||||
} | |||||
return tagNames, nil | |||||
// GetTags returns all tags of the repository. | |||||
func (repo *Repository) GetTags() (tags []string, err error) { | |||||
tags, _, err = callShowRef(repo.Path, TagPrefix, "--tags", 0, 0) | |||||
return | |||||
} | } | ||||
// GetTagType gets the type of the tag, either commit (simple) or tag (annotated) | // GetTagType gets the type of the tag, either commit (simple) or tag (annotated) | ||||
@@ -140,3 +140,11 @@ func ParseBool(value string) (result bool, valid bool) { | |||||
} | } | ||||
return intValue != 0, true | return intValue != 0, true | ||||
} | } | ||||
// ConcatenateError concatenats an error with stderr string | |||||
func ConcatenateError(err error, stderr string) error { | |||||
if len(stderr) == 0 { | |||||
return err | |||||
} | |||||
return fmt.Errorf("%w - %s", err, stderr) | |||||
} |
@@ -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) + | ||||
@@ -23,9 +23,10 @@ func GetBranch(repo *models.Repository, branch string) (*git.Branch, error) { | |||||
return gitRepo.GetBranch(branch) | return gitRepo.GetBranch(branch) | ||||
} | } | ||||
// GetBranches returns all the branches of a repository | |||||
func GetBranches(repo *models.Repository) ([]*git.Branch, error) { | |||||
return git.GetBranchesByPath(repo.RepoPath()) | |||||
// GetBranches returns branches from the repository, skipping skip initial branches and | |||||
// returning at most limit branches, or all branches if limit is 0. | |||||
func GetBranches(repo *models.Repository, skip, limit int) ([]*git.Branch, int, error) { | |||||
return git.GetBranchesByPath(repo.RepoPath(), skip, limit) | |||||
} | } | ||||
// checkBranchName validates branch name with existing repository branches | // checkBranchName validates branch name with existing repository branches | ||||
@@ -36,7 +37,7 @@ func checkBranchName(repo *models.Repository, name string) error { | |||||
} | } | ||||
defer gitRepo.Close() | defer gitRepo.Close() | ||||
branches, err := GetBranches(repo) | |||||
branches, _, err := GetBranches(repo, 0, 0) | |||||
if err != nil { | if err != nil { | ||||
return err | return err | ||||
} | } | ||||
@@ -439,14 +439,15 @@ var ( | |||||
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 | |||||
//benchmark config | //benchmark config | ||||
IsBenchmarkEnabled bool | IsBenchmarkEnabled bool | ||||
@@ -549,7 +550,7 @@ var ( | |||||
RecordBeginTime string | RecordBeginTime string | ||||
IgnoreMirrorRepo bool | IgnoreMirrorRepo bool | ||||
}{} | }{} | ||||
Warn_Notify_Mails []string | Warn_Notify_Mails []string | ||||
) | ) | ||||
@@ -1216,8 +1217,8 @@ 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") | ||||
@@ -1225,10 +1226,11 @@ func NewContext() { | |||||
DecompressOBSTaskName = sec.Key("DecompressOBSTaskName").MustString("LabelDecompressOBSQueue") | DecompressOBSTaskName = sec.Key("DecompressOBSTaskName").MustString("LabelDecompressOBSQueue") | ||||
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("") | ||||
@@ -1236,31 +1238,31 @@ func NewContext() { | |||||
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/") | |||||
BenchmarkCode = sec.Key("BENCHMARKCODE").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/") | |||||
Snn4imagenetCode = sec.Key("SNN4IMAGENETCODE").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/") | |||||
BrainScoreCode = sec.Key("BRAINSCORECODE").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 +1270,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 +1288,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 +1315,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) | ||||
@@ -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 | ||||
@@ -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 | |||||
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,6 +835,10 @@ 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=描述字数不超过256个字符 | |||||
modelarts.model_name=模型名称 | |||||
modelarts.model_size=模型大小 | |||||
modelarts.import_model=导入模型 | |||||
modelarts.train_job.new_place=描述字数不超过255个字符 | modelarts.train_job.new_place=描述字数不超过255个字符 | ||||
modelarts.modify=修改 | modelarts.modify=修改 | ||||
modelarts.current_version=当前版本 | modelarts.current_version=当前版本 | ||||
@@ -886,6 +895,18 @@ 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 = 召回率 | |||||
template.items=模板选项 | template.items=模板选项 | ||||
template.git_content=Git数据(默认分支) | template.git_content=Git数据(默认分支) | ||||
@@ -1565,6 +1586,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=使用外部的任务管理系统 | ||||
@@ -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> |
@@ -204,7 +204,7 @@ func ListBranches(ctx *context.APIContext) { | |||||
// "200": | // "200": | ||||
// "$ref": "#/responses/BranchList" | // "$ref": "#/responses/BranchList" | ||||
branches, err := repo_module.GetBranches(ctx.Repo.Repository) | |||||
branches, _, err := repo_module.GetBranches(ctx.Repo.Repository,0,0) | |||||
if err != nil { | if err != nil { | ||||
ctx.Error(http.StatusInternalServerError, "GetBranches", err) | ctx.Error(http.StatusInternalServerError, "GetBranches", err) | ||||
return | return | ||||
@@ -0,0 +1,513 @@ | |||||
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) | |||||
//aiTask, err := models.GetCloudbrainByJobID(jobId) | |||||
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, "") | |||||
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) | |||||
//taskConfigInfo,err := models.GetCloudbrainByJobIDAndVersionName(jobId,aiTask.VersionName) | |||||
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, | |||||
UserName: ctx.User.Name, | |||||
UserRelAvatarLink: ctx.User.RelAvatarLink(), | |||||
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) (string, int64, error) { | |||||
objectkey := strings.TrimPrefix(path.Join(setting.TrainJobModelPath, jobName, setting.OutPutPath, parentDir), "/") | |||||
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) | |||||
ctx.JSON(http.StatusOK, models) | |||||
} | |||||
func ShowOneVersionOtherModel(ctx *context.Context) { | |||||
repoId := ctx.Repo.Repository.ID | |||||
name := ctx.Query("name") | |||||
aimodels := models.QueryModelByName(name, repoId) | |||||
for _, model := range aimodels { | |||||
log.Info("model=" + model.Name) | |||||
log.Info("model.UserId=" + fmt.Sprint(model.UserId)) | |||||
model.IsCanOper = isOper(ctx, model.UserId) | |||||
} | |||||
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.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 | |||||
} | |||||
repoId := ctx.Repo.Repository.ID | |||||
Type := -1 | |||||
modelResult, count, err := models.QueryModel(&models.AiModelQueryOptions{ | |||||
ListOptions: models.ListOptions{ | |||||
Page: page, | |||||
PageSize: setting.UI.IssuePagingNum, | |||||
}, | |||||
RepoID: repoId, | |||||
Type: Type, | |||||
New: MODEL_LATEST, | |||||
}) | |||||
if err != nil { | |||||
ctx.ServerError("Cloudbrain", err) | |||||
return | |||||
} | |||||
for _, model := range modelResult { | |||||
log.Info("model=" + model.Name) | |||||
log.Info("model.UserId=" + fmt.Sprint(model.UserId)) | |||||
model.IsCanOper = isOper(ctx, model.UserId) | |||||
} | |||||
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") | |||||
} | |||||
} |
@@ -181,7 +181,7 @@ func deleteBranch(ctx *context.Context, branchName string) error { | |||||
} | } | ||||
func loadBranches(ctx *context.Context) []*Branch { | func loadBranches(ctx *context.Context) []*Branch { | ||||
rawBranches, err := repo_module.GetBranches(ctx.Repo.Repository) | |||||
rawBranches, _, err := repo_module.GetBranches(ctx.Repo.Repository, 0, 0) | |||||
if err != nil { | if err != nil { | ||||
ctx.ServerError("GetBranches", err) | ctx.ServerError("GetBranches", err) | ||||
return nil | return nil | ||||
@@ -74,12 +74,13 @@ func CloudBrainIndex(ctx *context.Context) { | |||||
timestamp := time.Now().Unix() | timestamp := time.Now().Unix() | ||||
for i, task := range ciTasks { | for i, task := range ciTasks { | ||||
if task.Status == string(models.JobRunning) && (timestamp-int64(task.Cloudbrain.CreatedUnix) > 10) { | if task.Status == string(models.JobRunning) && (timestamp-int64(task.Cloudbrain.CreatedUnix) > 10) { | ||||
ciTasks[i].CanDebug = true | |||||
ciTasks[i].CanDebug = cloudbrain.CanCreateOrDebugJob(ctx) | |||||
} else { | } else { | ||||
ciTasks[i].CanDebug = false | ciTasks[i].CanDebug = false | ||||
} | } | ||||
ciTasks[i].CanDel = models.CanDelJob(ctx.IsSigned, ctx.User, task) | |||||
ciTasks[i].CanDel = cloudbrain.CanDeleteDebugJob(ctx, &task.Cloudbrain) | |||||
} | } | ||||
pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, 5) | pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, 5) | ||||
@@ -88,6 +89,7 @@ func CloudBrainIndex(ctx *context.Context) { | |||||
ctx.Data["PageIsCloudBrain"] = true | ctx.Data["PageIsCloudBrain"] = true | ||||
ctx.Data["Tasks"] = ciTasks | ctx.Data["Tasks"] = ciTasks | ||||
ctx.Data["CanCreate"] = cloudbrain.CanCreateOrDebugJob(ctx) | |||||
ctx.HTML(200, tplCloudBrainIndex) | ctx.HTML(200, tplCloudBrainIndex) | ||||
} | } | ||||
@@ -216,7 +218,22 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { | |||||
return | return | ||||
} | } | ||||
_, err := models.GetCloudbrainByName(jobName) | |||||
count, err := models.GetCloudbrainCountByUserID(ctx.User.ID) | |||||
if err != nil { | |||||
log.Error("GetCloudbrainCountByUserID failed:%v", err, ctx.Data["MsgID"]) | |||||
cloudBrainNewDataPrepare(ctx) | |||||
ctx.RenderWithErr("system error", tplCloudBrainNew, &form) | |||||
return | |||||
} else { | |||||
if count >= 1 { | |||||
log.Error("the user already has running or waiting task", ctx.Data["MsgID"]) | |||||
cloudBrainNewDataPrepare(ctx) | |||||
ctx.RenderWithErr("you have already a running or waiting task, can not create more", tplCloudBrainNew, &form) | |||||
return | |||||
} | |||||
} | |||||
_, err = models.GetCloudbrainByName(jobName) | |||||
if err == nil { | if err == nil { | ||||
log.Error("the job name did already exist", ctx.Data["MsgID"]) | log.Error("the job name did already exist", ctx.Data["MsgID"]) | ||||
cloudBrainNewDataPrepare(ctx) | cloudBrainNewDataPrepare(ctx) | ||||
@@ -232,6 +249,7 @@ 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 | modelPath := setting.JobPath + jobName + cloudbrain.ModelMountPath | ||||
err = os.MkdirAll(modelPath, os.ModePerm) | err = os.MkdirAll(modelPath, os.ModePerm) | ||||
@@ -250,16 +268,19 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { | |||||
} | } | ||||
} | } | ||||
downloadRateCode(repo, jobName, setting.BenchmarkCode, benchmarkPath, form.BenchmarkCategory, gpuType) | downloadRateCode(repo, jobName, setting.BenchmarkCode, 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.Snn4imagenetCode, 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.BrainScoreCode, 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, modelPath, benchmarkPath, snn4imagenetPath, brainScorePath, jobType, gpuQueue, resourceSpecId) | ||||
@@ -323,7 +344,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) | ||||
@@ -340,7 +361,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) | ||||
@@ -437,14 +458,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) | |||||
} | } | ||||
} | } | ||||
@@ -513,10 +542,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 | ||||
} | } | ||||
@@ -576,7 +605,7 @@ 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 := setting.JobPath + jobName + "/model/" | ||||
if parentDir == "" { | if parentDir == "" { | ||||
@@ -678,8 +707,8 @@ func downloadRateCode(repo *models.Repository, taskName, gitPath, codePath, benc | |||||
command := "git clone " + gitPath + " " + codePath | command := "git clone " + gitPath + " " + codePath | ||||
cmd := exec.Command("/bin/bash", "-c", command) | cmd := exec.Command("/bin/bash", "-c", command) | ||||
output, err := cmd.Output() | |||||
log.Info(string(output)) | |||||
_, err = cmd.Output() | |||||
if err != nil { | if err != nil { | ||||
log.Error("exec.Command(%s) failed:%v", command, err) | log.Error("exec.Command(%s) failed:%v", command, err) | ||||
return err | return err | ||||
@@ -716,6 +745,33 @@ 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 SyncCloudbrainStatus() { | func SyncCloudbrainStatus() { | ||||
cloudBrains, err := models.GetCloudBrainUnStoppedJob() | cloudBrains, err := models.GetCloudBrainUnStoppedJob() | ||||
if err != nil { | if err != nil { | ||||
@@ -507,7 +507,7 @@ func getBranchesForRepo(user *models.User, repo *models.Repository) (bool, []str | |||||
} | } | ||||
defer gitRepo.Close() | defer gitRepo.Close() | ||||
branches, err := gitRepo.GetBranches() | |||||
branches, _, err := gitRepo.GetBranches(0, 0) | |||||
if err != nil { | if err != nil { | ||||
return false, nil, err | return false, nil, err | ||||
} | } | ||||
@@ -528,7 +528,7 @@ func CompareDiff(ctx *context.Context) { | |||||
} | } | ||||
if ctx.Data["PageIsComparePull"] == true { | if ctx.Data["PageIsComparePull"] == true { | ||||
headBranches, err := headGitRepo.GetBranches() | |||||
headBranches, _, err := headGitRepo.GetBranches(0,0) | |||||
if err != nil { | if err != nil { | ||||
ctx.ServerError("GetBranches", err) | ctx.ServerError("GetBranches", err) | ||||
return | 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 | ||||
@@ -424,7 +424,7 @@ func RetrieveRepoMetas(ctx *context.Context, repo *models.Repository, isPull boo | |||||
return nil | return nil | ||||
} | } | ||||
brs, err := ctx.Repo.GitRepo.GetBranches() | |||||
brs, _, err := ctx.Repo.GitRepo.GetBranches(0,0) | |||||
if err != nil { | if err != nil { | ||||
ctx.ServerError("GetBranches", err) | ctx.ServerError("GetBranches", err) | ||||
return nil | return nil | ||||
@@ -11,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" | ||||
@@ -68,10 +70,11 @@ func NotebookIndex(ctx *context.Context) { | |||||
for i, task := range ciTasks { | for i, task := range ciTasks { | ||||
if task.Status == string(models.JobRunning) { | if task.Status == string(models.JobRunning) { | ||||
ciTasks[i].CanDebug = true | |||||
ciTasks[i].CanDebug = cloudbrain.CanCreateOrDebugJob(ctx) | |||||
} else { | } else { | ||||
ciTasks[i].CanDebug = false | ciTasks[i].CanDebug = false | ||||
} | } | ||||
ciTasks[i].CanDel = cloudbrain.CanDeleteDebugJob(ctx, &task.Cloudbrain) | |||||
} | } | ||||
pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, 5) | pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, 5) | ||||
@@ -80,6 +83,7 @@ func NotebookIndex(ctx *context.Context) { | |||||
ctx.Data["PageIsCloudBrain"] = true | ctx.Data["PageIsCloudBrain"] = true | ||||
ctx.Data["Tasks"] = ciTasks | ctx.Data["Tasks"] = ciTasks | ||||
ctx.Data["CanCreate"] = cloudbrain.CanCreateOrDebugJob(ctx) | |||||
ctx.HTML(200, tplModelArtsNotebookIndex) | ctx.HTML(200, tplModelArtsNotebookIndex) | ||||
} | } | ||||
@@ -115,7 +119,22 @@ func NotebookCreate(ctx *context.Context, form auth.CreateModelArtsNotebookForm) | |||||
description := form.Description | description := form.Description | ||||
flavor := form.Flavor | flavor := form.Flavor | ||||
err := modelarts.GenerateTask(ctx, jobName, uuid, description, flavor) | |||||
count, err := models.GetCloudbrainNotebookCountByUserID(ctx.User.ID) | |||||
if err != nil { | |||||
log.Error("GetCloudbrainNotebookCountByUserID failed:%v", err, ctx.Data["MsgID"]) | |||||
cloudBrainNewDataPrepare(ctx) | |||||
ctx.RenderWithErr("system error", tplModelArtsNotebookNew, &form) | |||||
return | |||||
} else { | |||||
if count >= 1 { | |||||
log.Error("the user already has running or waiting task", ctx.Data["MsgID"]) | |||||
cloudBrainNewDataPrepare(ctx) | |||||
ctx.RenderWithErr("you have already a running or waiting task, can not create more", tplModelArtsNotebookNew, &form) | |||||
return | |||||
} | |||||
} | |||||
err = modelarts.GenerateTask(ctx, jobName, uuid, description, flavor) | |||||
if err != nil { | if err != nil { | ||||
ctx.RenderWithErr(err.Error(), tplModelArtsNotebookNew, &form) | ctx.RenderWithErr(err.Error(), tplModelArtsNotebookNew, &form) | ||||
return | return | ||||
@@ -286,12 +305,18 @@ func TrainJobIndex(ctx *context.Context) { | |||||
return | return | ||||
} | } | ||||
for i, task := range tasks { | |||||
tasks[i].CanDel = cloudbrain.CanDeleteTrainJob(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.HTML(200, tplModelArtsTrainJobIndex) | ctx.HTML(200, tplModelArtsTrainJobIndex) | ||||
} | } | ||||
@@ -360,18 +385,6 @@ 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 | ||||
Branches, err := ctx.Repo.GitRepo.GetBranches() | |||||
if err != nil { | |||||
log.Error("GetBranches failed:%v", err) | |||||
ctx.ServerError("GetBranches error:", err) | |||||
return err | |||||
} | |||||
if Branches != nil { | |||||
ctx.Data["Branches"] = Branches | |||||
} | |||||
ctx.Data["BranchesCount"] = len(Branches) | |||||
ctx.Data["params"] = "" | ctx.Data["params"] = "" | ||||
ctx.Data["branchName"] = ctx.Repo.BranchName | ctx.Data["branchName"] = ctx.Repo.BranchName | ||||
@@ -442,14 +455,6 @@ func trainJobErrorNewDataPrepare(ctx *context.Context, form auth.CreateModelArts | |||||
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 | ||||
Branches, err := ctx.Repo.GitRepo.GetBranches() | |||||
if err != nil { | |||||
ctx.ServerError("GetBranches error:", err) | |||||
return err | |||||
} | |||||
ctx.Data["Branches"] = Branches | |||||
ctx.Data["BranchesCount"] = len(Branches) | |||||
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 { | ||||
ctx.ServerError("getConfigList failed:", err) | ctx.ServerError("getConfigList failed:", err) | ||||
@@ -545,13 +550,13 @@ func trainJobNewVersionDataPrepare(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 | ||||
Branches, err := ctx.Repo.GitRepo.GetBranches() | |||||
branches, _, err := ctx.Repo.GitRepo.GetBranches(0, 0) | |||||
if err != nil { | if err != nil { | ||||
ctx.ServerError("GetBranches error:", err) | ctx.ServerError("GetBranches error:", err) | ||||
return err | return err | ||||
} | } | ||||
ctx.Data["branches"] = Branches | |||||
ctx.Data["branches"] = branches | |||||
ctx.Data["branch_name"] = task.BranchName | ctx.Data["branch_name"] = task.BranchName | ||||
ctx.Data["description"] = task.Description | ctx.Data["description"] = task.Description | ||||
ctx.Data["boot_file"] = task.BootFile | ctx.Data["boot_file"] = task.BootFile | ||||
@@ -634,12 +639,12 @@ func versionErrorDataPrepare(ctx *context.Context, form auth.CreateModelArtsTrai | |||||
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 | ||||
Branches, err := ctx.Repo.GitRepo.GetBranches() | |||||
branches, _, err := ctx.Repo.GitRepo.GetBranches(0, 0) | |||||
if err != nil { | if err != nil { | ||||
ctx.ServerError("GetBranches error:", err) | ctx.ServerError("GetBranches error:", err) | ||||
return err | return err | ||||
} | } | ||||
ctx.Data["branches"] = Branches | |||||
ctx.Data["branches"] = branches | |||||
ctx.Data["description"] = form.Description | ctx.Data["description"] = form.Description | ||||
ctx.Data["dataset_name"] = task.DatasetName | ctx.Data["dataset_name"] = task.DatasetName | ||||
ctx.Data["work_server_number"] = form.WorkServerNumber | ctx.Data["work_server_number"] = form.WorkServerNumber | ||||
@@ -687,6 +692,21 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||||
VersionCount := modelarts.VersionCount | VersionCount := modelarts.VersionCount | ||||
EngineName := form.EngineName | EngineName := form.EngineName | ||||
count, err := models.GetCloudbrainTrainJobCountByUserID(ctx.User.ID) | |||||
if err != nil { | |||||
log.Error("GetCloudbrainTrainJobCountByUserID failed:%v", err, ctx.Data["MsgID"]) | |||||
trainJobErrorNewDataPrepare(ctx, form) | |||||
ctx.RenderWithErr("system error", tplModelArtsTrainJobNew, &form) | |||||
return | |||||
} else { | |||||
if count >= 1 { | |||||
log.Error("the user already has running or waiting task", ctx.Data["MsgID"]) | |||||
trainJobErrorNewDataPrepare(ctx, form) | |||||
ctx.RenderWithErr("you have already a running or waiting task, can not create more", tplModelArtsTrainJobNew, &form) | |||||
return | |||||
} | |||||
} | |||||
if err := paramCheckCreateTrainJob(form); err != nil { | if err := paramCheckCreateTrainJob(form); err != nil { | ||||
log.Error("paramCheckCreateTrainJob failed:(%v)", err) | log.Error("paramCheckCreateTrainJob failed:(%v)", err) | ||||
trainJobErrorNewDataPrepare(ctx, form) | trainJobErrorNewDataPrepare(ctx, form) | ||||
@@ -839,7 +859,7 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||||
return | return | ||||
} | } | ||||
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()) | ||||
trainJobErrorNewDataPrepare(ctx, form) | trainJobErrorNewDataPrepare(ctx, form) | ||||
@@ -853,6 +873,21 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ | |||||
ctx.Data["PageIsTrainJob"] = true | ctx.Data["PageIsTrainJob"] = true | ||||
var jobID = ctx.Params(":jobid") | var jobID = ctx.Params(":jobid") | ||||
count, err := models.GetCloudbrainTrainJobCountByUserID(ctx.User.ID) | |||||
if err != nil { | |||||
log.Error("GetCloudbrainTrainJobCountByUserID failed:%v", err, ctx.Data["MsgID"]) | |||||
versionErrorDataPrepare(ctx, form) | |||||
ctx.RenderWithErr("system error", tplModelArtsTrainJobVersionNew, &form) | |||||
return | |||||
} else { | |||||
if count >= 1 { | |||||
log.Error("the user already has running or waiting task", ctx.Data["MsgID"]) | |||||
versionErrorDataPrepare(ctx, form) | |||||
ctx.RenderWithErr("you have already a running or waiting task, can not create more", tplModelArtsTrainJobVersionNew, &form) | |||||
return | |||||
} | |||||
} | |||||
latestTask, err := models.GetCloudbrainByJobIDAndIsLatestVersion(jobID, modelarts.IsLatestVersion) | latestTask, err := models.GetCloudbrainByJobIDAndIsLatestVersion(jobID, modelarts.IsLatestVersion) | ||||
if err != nil { | if err != nil { | ||||
ctx.ServerError("GetCloudbrainByJobIDAndIsLatestVersion faild:", err) | ctx.ServerError("GetCloudbrainByJobIDAndIsLatestVersion faild:", err) | ||||
@@ -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")) | ||||
@@ -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" | ||||
@@ -612,6 +614,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) | ||||
@@ -957,26 +961,43 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
m.Get("", reqRepoCloudBrainReader, repo.CloudBrainIndex) | 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("/modelarts", func() { | m.Group("/modelarts", func() { | ||||
m.Group("/notebook", func() { | m.Group("/notebook", func() { | ||||
m.Get("", reqRepoCloudBrainReader, repo.NotebookIndex) | 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 +1007,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) | ||||
@@ -252,7 +252,7 @@ func runSync(m *models.Mirror) ([]*mirrorSyncResult, bool) { | |||||
} | } | ||||
} | } | ||||
branches, err := repo_module.GetBranches(m.Repo) | |||||
branches, _, err := repo_module.GetBranches(m.Repo,0,0) | |||||
if err != nil { | if err != nil { | ||||
log.Error("GetBranches: %v", err) | log.Error("GetBranches: %v", err) | ||||
return nil, false | return nil, false | ||||
@@ -452,7 +452,7 @@ func CloseBranchPulls(doer *models.User, repoID int64, branch string) error { | |||||
// CloseRepoBranchesPulls close all pull requests which head branches are in the given repository | // CloseRepoBranchesPulls close all pull requests which head branches are in the given repository | ||||
func CloseRepoBranchesPulls(doer *models.User, repo *models.Repository) error { | func CloseRepoBranchesPulls(doer *models.User, repo *models.Repository) error { | ||||
branches, err := git.GetBranchesByPath(repo.RepoPath()) | |||||
branches, _, err := git.GetBranchesByPath(repo.RepoPath(), 0, 0) | |||||
if err != nil { | if err != nil { | ||||
return err | return err | ||||
} | } | ||||
@@ -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" > | |||||
<div class="dropdown-menu"> | |||||
<a class=" item" href="/dashboard"> | |||||
<span > {{.i18n.Tr "index"}}   <i class="dropdown icon"></i></span> | |||||
</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 .IsOperator}} | {{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"> | |||||
<div class="dropdown-menu"> | |||||
<a class=" item" href="/user/login"> | |||||
<span > {{.i18n.Tr "home"}}   <i class="dropdown icon"></i></span> | |||||
</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 .IsOperator}} | {{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="{{$.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 +190,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"}} | ||||
@@ -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" > | |||||
<div class="dropdown-menu"> | |||||
<a class=" item" href="/dashboard"> | |||||
<span > {{.i18n.Tr "index"}}   <i class="dropdown icon"></i></span> | |||||
</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 .IsOperator}} | {{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" > | |||||
<div class="dropdown-menu"> | |||||
<a class=" item" href="/user/login"> | |||||
<span > {{.i18n.Tr "home"}}   <i class="dropdown icon"></i></span> | |||||
</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 .IsOperator}} | {{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" > | |||||
<div class="dropdown-menu"> | |||||
<a class=" item" href="/dashboard"> | |||||
<span > {{.i18n.Tr "index"}}   <i class="dropdown icon"></i></span> | |||||
</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 .IsOperator}} | {{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" > | |||||
<div class="dropdown-menu"> | |||||
<a class=" item" href="/user/login"> | |||||
<span > {{.i18n.Tr "home"}}   <i class="dropdown icon"></i></span> | |||||
</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 .IsOperator}} | {{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,575 @@ | |||||
<!-- 头部导航栏 --> | |||||
{{template "base/head" .}} | |||||
<style> | |||||
.label_after::after{ | |||||
margin: -.2em 0 0 .2em; | |||||
content: '\00a0'; | |||||
} | |||||
.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; | |||||
} | |||||
.time-show{ | |||||
font-size: 10px; | |||||
margin-top: 0.4rem; | |||||
display: inline-block; | |||||
} | |||||
</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"> | |||||
<div class="ui two column stackable grid "> | |||||
<div class="column"> | |||||
<div class="ui blue small menu compact selectcloudbrain"> | |||||
<a class="active item" href="{{.RepoLink}}/debugjob">{{$.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);"> 全部</div> | |||||
<i class="dropdown icon"></i> | |||||
<div class="menu"> | |||||
<a class="active item" href="{{.RepoLink}}/debugjob" data-value="11">全部</a> | |||||
<a class="item" href="{{.RepoLink}}/cloudbrain" data-value="22">CPU / GPU</a> | |||||
<a class="item" href="{{.RepoLink}}/modelarts/notebook" data-value="33">Ascend NPU</a> | |||||
</div> | |||||
</div> | |||||
{{if .Permission.CanWrite $.UnitTypeCloudBrain}} | |||||
<a class="ui green button" href="{{.RepoLink}}/cloudbrain/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="dataset list"> | |||||
<div class="ui grid stackable" style="background: #f0f0f0;;"> | |||||
<div class="row"> | |||||
<div class="four wide column"> | |||||
<span style="margin:0 6px">{{$.i18n.Tr "repo.cloudbrain_task"}}</span> | |||||
</div> | |||||
<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 class="one wide column text center"> | |||||
<span>{{$.i18n.Tr "repo.cloudbrain_creator"}}</span> | |||||
</div> | |||||
<div class="five wide column text center"> | |||||
<span>{{$.i18n.Tr "repo.cloudbrain_operate"}}</span> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
{{range .Tasks}} | |||||
<div class="ui grid stackable item"> | |||||
<div class="row"> | |||||
<!-- 任务名 --> | |||||
<div class="four wide column"> | |||||
<a class="title" href="{{$.Link}}/{{.JobID}}" title="{{.JobName}}" style="font-size: 14px;"> | |||||
<span class="fitted text_over" style="width: 90%;vertical-align: middle;">{{.JobName}}</span> | |||||
</a> | |||||
</div> | |||||
<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> | |||||
</div> | |||||
<div class="two wide column text center"> | |||||
<!-- 任务创建时间 --> | |||||
<span style="font-size: 12px;margin-left: 0.4rem;" class="">{{TimeSinceUnix .Cloudbrain.CreatedUnix $.Lang}}</span> | |||||
</div> | |||||
<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}} | |||||
<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 center"> | |||||
<div class="ui compact buttons"> | |||||
{{if and (ne .Status "WAITING") (ne .JobType "DEBUG")}} | |||||
<a class="ui basic button" href="{{$.Link}}/{{.JobID}}/rate" target="_blank"> | |||||
评分 | |||||
</a> | |||||
{{end}} | |||||
<!-- 调试 --> | |||||
{{if $.Permission.CanWrite $.UnitTypeCloudBrain}} | |||||
{{if eq .ComputeResource "CPU/GPU"}} | |||||
<a id="model-debug-{{.JobID}}" class="ui basic {{if not .CanDebug}}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 not .CanDebug}}disabled {{else}}blue {{end}}button" href="{{$.RepoLink}}/modelarts/notebook/{{.JobID}}/debug" target="_blank"> | |||||
{{$.i18n.Tr "repo.debug"}} | |||||
</a> | |||||
{{end}} | |||||
{{else}} | |||||
<a class="ui basic disabled button" href="{{$.Link}}/{{.JobID}}/debug" target="_blank"> | |||||
{{$.i18n.Tr "repo.debug"}} | |||||
</a> | |||||
{{end}} | |||||
<!-- 停止 --> | |||||
<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}} | |||||
{{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();"> | |||||
{{$.i18n.Tr "repo.stop"}} | |||||
</a> | |||||
{{else}} | |||||
<a class="ui basic disabled button" onclick="document.getElementById('stopForm-{{.JobID}}').submit();"> | |||||
{{$.i18n.Tr "repo.stop"}} | |||||
</a> | |||||
{{end}} | |||||
<input type="hidden" name="debugListType" value="all"> | |||||
</form> | |||||
</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}}" style="{{if eq .ComputeResource "CPU/GPU"}} visibility: visible {{else}} visibility: hidden{{end}}" 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" style="{{if eq .ComputeResource "CPU/GPU"}} visibility: visible {{else}} visibility: hidden{{end}}" value="{{.CanDebug}}">{{$.i18n.Tr "repo.submit_image"}}</a> | |||||
{{end}} | |||||
</div> | |||||
{{.CanDel}} | |||||
<!-- 删除任务 --> | |||||
<form class="ui compact buttons" 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}} | |||||
<!-- {{if not .CanDel}}disabled {{else}} blue {{end}} --> | |||||
<a id="model-delete-{{.JobID}}" class="ui basic blue 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> | |||||
</div> | |||||
<!-- 镜像列表弹窗 --> | |||||
<div id="imageModal" class="modal" style="display: none;"> | |||||
<div class="modal-content"> | |||||
<!-- 表格 --> | |||||
<div class="ui form"> | |||||
<form id="commitImageForm" action="{{$.RepoLink}}/cloudbrain/{{.JobID}}/commit_image" method="post" target="iframeContent"> | |||||
{{$.CsrfTokenHtml}} | |||||
<div class="row"> | |||||
<p style="display: inline;">提交任务镜像</p> | |||||
<span class="close">×</span> | |||||
</div> | |||||
<div class="ui divider"></div> | |||||
<div class="inline required field dis"> | |||||
<label>镜像标签:</label> | |||||
<input name="tag" id="image_tag" tabindex="3" autofocus required maxlength="254" style="width:75%"> | |||||
</div> | |||||
<div class="inline field"> | |||||
<label class="label_after">镜像描述:</label> | |||||
<textarea name="description" maxlength="254" rows="8" style="width:75%;margin-left: 0.2em;"></textarea> | |||||
</div> | |||||
<div class="ui divider"></div> | |||||
<div class="inline field"> | |||||
<label></label> | |||||
<button class="ui green button" onclick="showmask()"> | |||||
{{$.i18n.Tr "repo.cloudbrain.commit_image"}} | |||||
</button> | |||||
</div> | |||||
</form> | |||||
</div> | |||||
</div> | |||||
</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> | |||||
// 调试和评分新开窗口 | |||||
console.log({{.Tasks}}) | |||||
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; | |||||
const computeResource = job.dataset.resource | |||||
const initArray = ['STOPPED','FAILED','START_FAILED','CREATE_FAILED'] | |||||
if (initArray.includes(job.textContent.trim())) { | |||||
return | |||||
} | |||||
const diffResource = computeResource == "NPU" ? 'modelarts/notebook' : 'cloudbrain' | |||||
$.get(`/api/v1/repos/${repoPath}/${diffResource}/${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==="RUNNING"){ | |||||
$('#model-debug-'+jobID).removeClass('disabled') | |||||
$('#model-debug-'+jobID).addClass('blue') | |||||
$('#model-image-'+jobID).removeClass('disabled') | |||||
$('#model-image-'+jobID).addClass('blue') | |||||
} | |||||
if(status!=="RUNNING"){ | |||||
$('#model-debug-'+jobID).removeClass('blue') | |||||
$('#model-debug-'+jobID).addClass('disabled') | |||||
$('#model-image-'+jobID).removeClass('blue') | |||||
$('#model-image-'+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') | |||||
} | |||||
}).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() { | |||||
var image_tag = !$('#image_tag').val() | |||||
console.log("image_tag",image_tag) | |||||
if(image_tag){ | |||||
return | |||||
} | |||||
$('#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> |
@@ -137,6 +137,12 @@ | |||||
{{svg "octicon-inbox" 16}} {{.i18n.Tr "datasets"}} | {{svg "octicon-inbox" 16}} {{.i18n.Tr "datasets"}} | ||||
</a> | </a> | ||||
{{end}} | {{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> | |||||
{{end}} | |||||
{{if .Permission.CanRead $.UnitTypeCloudBrain}} | {{if .Permission.CanRead $.UnitTypeCloudBrain}} | ||||
<a class="{{if .PageIsCloudBrain}}active{{end}} item" href="{{.RepoLink}}/cloudbrain"> | <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> | <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> | ||||
@@ -164,86 +170,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,187 +1,6 @@ | |||||
<!-- 头部导航栏 --> | <!-- 头部导航栏 --> | ||||
{{template "base/head" .}} | {{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="mask"> | ||||
<div id="loadingPage"> | <div id="loadingPage"> | ||||
@@ -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"> | ||||
@@ -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; | ||||
} | } | ||||
@@ -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> | ||||
@@ -474,6 +474,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(); | // $('.ui.style.accordion').accordion(); | ||||
@@ -709,11 +710,13 @@ td, th { | |||||
} | } | ||||
function logScroll(version_name) { | function logScroll(version_name) { | ||||
let container = document.querySelector(`#log${version_name}`) | let container = document.querySelector(`#log${version_name}`) | ||||
let scrollTop = container.scrollTop | let scrollTop = container.scrollTop | ||||
let scrollHeight = container.scrollHeight | let scrollHeight = container.scrollHeight | ||||
let clientHeight = container.clientHeight | let clientHeight = container.clientHeight | ||||
if(parseInt(scrollTop) + clientHeight == scrollHeight || parseInt(scrollTop) + clientHeight +1 == scrollHeight || parseInt(scrollTop) + clientHeight - 1 == scrollHeight){ | |||||
let scrollLeft = container.scrollLeft | |||||
if((parseInt(scrollTop) + clientHeight == scrollHeight || parseInt(scrollTop) + clientHeight +1 == scrollHeight || parseInt(scrollTop) + clientHeight - 1 == scrollHeight) && (scrollLeft===0)){ | |||||
let end_line = $(`#log${version_name} input[name=end_line]`).val() | let end_line = $(`#log${version_name} input[name=end_line]`).val() | ||||
$.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?version_name=${version_name}&base_line=${end_line}&lines=50&order=desc`, (data) => { | $.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?version_name=${version_name}&base_line=${end_line}&lines=50&order=desc`, (data) => { | ||||
if (data.Lines == 0){ | if (data.Lines == 0){ | ||||
@@ -736,7 +739,7 @@ td, th { | |||||
console.log(err); | console.log(err); | ||||
}); | }); | ||||
} | } | ||||
if(scrollTop == 0){ | |||||
if(scrollTop == 0 && scrollLeft==0){ | |||||
let start_line = $(`#log${version_name} input[name=start_line]`).val() | let start_line = $(`#log${version_name} input[name=start_line]`).val() | ||||
$.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?version_name=${version_name}&base_line=${start_line}&lines=50&order=asc`, (data) => { | $.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?version_name=${version_name}&base_line=${start_line}&lines=50&order=asc`, (data) => { | ||||
if (data.Lines == 0){ | if (data.Lines == 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"> | ||||
@@ -346,7 +265,7 @@ | |||||
{{template "base/footer" .}} | {{template "base/footer" .}} | ||||
<script> | <script> | ||||
let url_href = location.pathname.split('create_version')[0] | |||||
let url_href = location.pathname.split('/create_version')[0] | |||||
let url_post = location.pathname | let url_post = location.pathname | ||||
let version_name = location.search.split('?version_name=')[1] | let version_name = location.search.split('?version_name=')[1] | ||||
$("#parents_version").val(version_name) | $("#parents_version").val(version_name) | ||||
@@ -0,0 +1,299 @@ | |||||
<!-- 头部导航栏 --> | |||||
{{template "base/head" .}} | |||||
<style> | |||||
.width70{ | |||||
width: 70% !important; | |||||
} | |||||
.width83{ | |||||
width: 83% !important; | |||||
} | |||||
.content-padding{ | |||||
padding: 40px !important; | |||||
} | |||||
</style> | |||||
<!-- 弹窗 --> | |||||
<div id="mask"> | |||||
<div id="loadingPage"> | |||||
<div class="rect1"></div> | |||||
<div class="rect2"></div> | |||||
<div class="rect3"></div> | |||||
<div class="rect4"></div> | |||||
<div class="rect5"></div> | |||||
</div> | |||||
</div> | |||||
{{$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 "> | |||||
<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"> | |||||
<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>导入新模型</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;" name="Label" maxlength="255"> | |||||
</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.cloudbrain.new"}} | |||||
</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(){ | |||||
$('.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').css('display','none') | |||||
} | |||||
}) | |||||
.modal('show') | |||||
} | |||||
$(function(){ | |||||
$('#choice_model').dropdown({ | |||||
onChange:function(value){ | |||||
$(".ui.dropdown.selection.search.width70").addClass("loading") | |||||
$("#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") | |||||
}) | |||||
} | |||||
function loadTrainVersion(value){ | |||||
$.get(`${repolink}/modelmanage/query_train_job_version?JobID=${value}`, (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>' | |||||
} | |||||
$("#job-version").append(train_html) | |||||
$(".ui.dropdown.selection.search.width70").removeClass("loading") | |||||
}) | |||||
} | |||||
function 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 | |||||
} | |||||
$('#submitId').click(function(){ | |||||
let flag=check() | |||||
if(flag){ | |||||
let data = $("#formId").serialize() | |||||
$("#mask").css({"display":"block","z-index":"9999"}) | |||||
$.ajax({ | |||||
url:url_href, | |||||
type:'POST', | |||||
data:data, | |||||
success:function(res){ | |||||
$('.ui.modal.second').modal('hide') | |||||
window.location.href=location.href | |||||
}, | |||||
error: function(xhr){ | |||||
// 隐藏 loading | |||||
// 只有请求不正常(状态码不为200)才会执行 | |||||
console.log("-------------",xhr) | |||||
$('.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 | |||||
} | |||||
}) | |||||
</script> | |||||
@@ -0,0 +1,218 @@ | |||||
{{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> | |||||
</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 initObj = transObj(versionData)[0] | |||||
let initModelAcc = transObj(versionData)[1] | |||||
let id= transObj(data)[2] | |||||
$('#showInfo').empty() | |||||
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++){ | |||||
html += `<option value="${data[i].Version}">${data[i].Version}</option>` | |||||
} | |||||
$('#dropdown').append(html) | |||||
let initObj = transObj(data)[0] | |||||
let initModelAcc = transObj(data)[1] | |||||
let id= transObj(data)[2] | |||||
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(text,id){ | |||||
$('#edit-td').replaceWith("<div id='edit-div' style='width:80%;display: inline-block;'><textarea id='textarea-value' rows='3' maxlength='255' style='width:80%;' id='edit-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 title="\'' + text + '\'" class="iword-elipsis">'+text+'</span><i class="pencil alternate icon" style="cursor:pointer;vertical-align: top;" id="editor" onclick="editorFn(\'' + text + '\',\'' + id + '\')"></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 title="\'' + description + '\'" class="iword-elipsis">'+description+'</span><i class="pencil alternate icon" style="cursor:pointer;vertical-align: top;" id="editor" onclick="editorFn(\'' + description + '\',\'' + id + '\')"></div>') | |||||
}) | |||||
} | |||||
function renderInfo(obj,accObj,id){ | |||||
let html = '' | |||||
html += '<div class="half-table">' | |||||
html += '<span class="model_header_text">基本信息</span>' | |||||
html += '<table class="tableStyle" style="margin-top:20px;">' | |||||
html += '<tbody>' | |||||
for(let key in obj){ | |||||
html += '<tr style="font-size: 12px;">' | |||||
html += `<td class="ti-text-form-label text-width80">${key}</td>` | |||||
if(key==="Description"){ | |||||
let description = obj[key] | |||||
html += '<td class="ti-text-form-content" ><div id="edit-td" style="display:flex"><span title="\'' + description + '\'" class="iword-elipsis">'+description+'</span><i class="pencil alternate icon" style="cursor:pointer;vertical-align: top;" id="editor" onclick="editorFn(\'' + description + '\',\'' + id + '\')"></div></td>' | |||||
}else{ | |||||
html += `<td class="ti-text-form-content word-elipsis"><span title="${obj[key]}">${obj[key]}</span></td>` | |||||
} | |||||
html += '</tr>' | |||||
} | |||||
html += '</tbody>' | |||||
html += '</table>' | |||||
html += '</div>' | |||||
html += '<div class="half-table">' | |||||
html += '<span class="model_header_text">模型精度</span>' | |||||
html += '<table class="tableStyle" style="margin-top:20px;">' | |||||
html += '<tbody>' | |||||
for(let key in accObj){ | |||||
html += '<tr style="font-size: 12px;">' | |||||
html += `<td class="ti-text-form-label text-width80">${key}</td>` | |||||
html += `<td class="ti-text-form-content word-elipsis">${accObj[key]}</td>` | |||||
html += '</tr>' | |||||
} | |||||
html += '</tbody>' | |||||
html += '</table>' | |||||
html += '</div>' | |||||
html += '<div style="clear: both;"></div>' | |||||
$('#showInfo').append(html) | |||||
} | |||||
</script> |
@@ -158,7 +158,14 @@ | |||||
<label>{{.i18n.Tr "repo.settings.cloudbrain_desc"}}</label> | <label>{{.i18n.Tr "repo.settings.cloudbrain_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> | |||||
{{$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> | ||||
@@ -0,0 +1,427 @@ | |||||
<template> | |||||
<div> | |||||
<div class="ui container" id="header"> | |||||
<el-row style="margin-top:15px;" v-loading.fullscreen.lock="fullscreenLoading"> | |||||
<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" :title="scope.row.UserName"> | |||||
<img class="ui avatar image" :src="scope.row.UserRelAvatarLink"> | |||||
</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)">创建新版本</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="[10]" | |||||
: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: [], | |||||
fullscreenLoading: false, | |||||
url:'', | |||||
isLoading:true, | |||||
loadNodeMap:new Map() | |||||
}; | |||||
}, | |||||
methods: { | |||||
load(tree, treeNode, resolve) { | |||||
this.loadNodeMap.set(tree.cName, tree.ID) | |||||
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) | |||||
}) | |||||
}, | |||||
tableHeaderStyle({row,column,rowIndex,columnIndex}){ | |||||
if(rowIndex===0){ | |||||
return 'background:#f5f5f6;color:#606266' | |||||
} | |||||
}, | |||||
handleSizeChange(val){ | |||||
this.params.size = val | |||||
this.getModelList() | |||||
}, | |||||
handleCurrentChange(val){ | |||||
this.params.page = val | |||||
this.getModelList() | |||||
}, | |||||
showcreateVue(name,version){ | |||||
$('.ui.modal.second') | |||||
.modal({ | |||||
centered: false, | |||||
onShow:function(){ | |||||
$('.ui.dimmer').css({"background-color":"rgb(136, 136, 136,0.7)"}) | |||||
$("#job-name").empty() | |||||
$('#name').val(name) | |||||
let version_string = versionAdd(version) | |||||
$('#version').val(version_string) | |||||
loadTrainList() | |||||
}, | |||||
onHide:function(){ | |||||
document.getElementById("formId").reset(); | |||||
$('#choice_model').dropdown('clear') | |||||
$('#choice_version').dropdown('clear') | |||||
$('.ui.dimmer').css({"background-color":""}) | |||||
} | |||||
}) | |||||
.modal('show') | |||||
}, | |||||
deleteModel(id,name){ | |||||
let tree={cName:name} | |||||
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.getModelList() | |||||
_this.loadrefresh(tree) | |||||
}) | |||||
flag = true | |||||
}, | |||||
onHidden: function() { | |||||
if (flag == false) { | |||||
$('.alert').html('您已取消操作').removeClass('alert-success').addClass('alert-danger').show().delay(1500).fadeOut(); | |||||
} | |||||
} | |||||
}) | |||||
.modal('show') | |||||
}, | |||||
loadrefresh(tree){ | |||||
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 | |||||
} | |||||
let id = this.loadNodeMap.get(tree.cName) | |||||
this.$set(this.$refs.table.store.states.lazyTreeNodeMap, id, tableData) | |||||
}) | |||||
}, | |||||
getModelList(){ | |||||
this.fullscreenLoading = false | |||||
this.$axios.get(location.href+'_api',{ | |||||
params:this.params | |||||
}).then((res)=>{ | |||||
$("#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 | |||||
this.fullscreenLoading = false | |||||
}) | |||||
}, | |||||
}, | |||||
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.getModelList() | |||||
this.url = location.href.split('show_model')[0] | |||||
} | |||||
}; | |||||
</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;} | |||||
/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> |
@@ -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) | ||||
@@ -4100,3 +4117,11 @@ $.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 | |||||
}); | |||||
} |
@@ -335,4 +335,187 @@ display: block; | |||||
margin-left: 4px !important; | margin-left: 4px !important; | ||||
color: #3291F8; | color: #3291F8; | ||||
} | |||||
.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; | |||||
} | |||||
.letf2{ | |||||
margin-left: -2px; | |||||
} | } |