@@ -167,7 +167,7 @@ func runWeb(ctx *cli.Context) error { | |||
if setting.EnablePprof { | |||
go func() { | |||
log.Info("Starting pprof server on localhost:6060") | |||
log.Info("%v", http.ListenAndServe("192.168.207.34:6060", nil)) | |||
log.Info("%v", http.ListenAndServe("localhost:6060", nil)) | |||
}() | |||
} | |||
@@ -0,0 +1,12 @@ | |||
{ | |||
"compute_resource": ["GPU", "GCU", "MLU", "ILUVATAR-GPGPU", "METAX-GPGPU"], | |||
"framework":["PyTorch","TensorFlow","MindSpore","PaddlePaddle","Other"], | |||
"framework_version":{ | |||
"PyTorch":["2.1.1","2.1.0","2.0.1","2.0.0", "1.13.1","1.13.0","1.12.1","1.12.0","1.11.0","1.10.1","1.10.0","1.9.1","1.9.0","1.6.0"], | |||
"TensorFlow":["2.15.0","2.14.1","2.13.1","2.13.0","2.12.1","2.12.0","2.11.1","2.11.0","2.10.1","2.9.3","2.9.2","2.8.4","2.8.3","2.7.4"], | |||
"MindSpore":["2.2.10","2.2.1","2.1.0","2.0.0","1.10.1","1.10.0"], | |||
"PaddlePaddle":["2.6.0","2.5.2","2.5.1","2.5.0","2.4.2","2.4.1","2.4.0","2.3.2","2.3.1","2.3.0","2.2.2"] | |||
}, | |||
"python":["3.13","3.12","3.11","3.10","3.9","3.8","3.7","3.6"], | |||
"cuda":["12.3","12.2","12.1","11.8","11.7","11.6","11.5","11.4","11.3","11.2","11.1","10.2","10.1","10.0"] | |||
} |
@@ -29,6 +29,7 @@ const ( | |||
urlGetResourceSpecs = urlOpenApiV1 + "resourcespec" | |||
urlGetAiCenter = urlOpenApiV1 + "sharescreen/aicenter" | |||
urlGetImages = urlOpenApiV1 + "image" | |||
urlListUserImages = urlOpenApiV1 + "listUserImage" | |||
urlNotebookJob = urlOpenApiV1 + "notebook" | |||
urlInferenceJob = urlOpenApiV1 + "inference" | |||
@@ -351,6 +352,8 @@ sendjob: | |||
_ = getToken() | |||
goto sendjob | |||
} | |||
jsonstr, _ := json.Marshal(result) | |||
log.Info("GetImages resp:", string(jsonstr)) | |||
if result.ErrorCode != 0 { | |||
log.Error("GetImages failed(%d): %s", result.ErrorCode, result.ErrorMsg) | |||
@@ -360,6 +363,45 @@ sendjob: | |||
return &result, nil | |||
} | |||
func GetUserImages(processorType string, jobType string) (*models.GetGrampusImagesResult, error) { | |||
checkSetting() | |||
client := getRestyClient() | |||
var result models.GetGrampusImagesResult | |||
retry := 0 | |||
queryType := "TrainJob" | |||
if jobType == string(models.JobTypeDebug) { | |||
queryType = "Notebook" | |||
} | |||
sendjob: | |||
_, err := client.R(). | |||
SetAuthToken(TOKEN). | |||
SetResult(&result). | |||
Get(HOST + urlListUserImages + "?processorType=" + processorType + "&trainType=" + queryType) | |||
if err != nil { | |||
return nil, fmt.Errorf("resty GetUserImages: %v", err) | |||
} | |||
if result.ErrorCode == errorIllegalToken && retry < 1 { | |||
retry++ | |||
log.Info("retry get token") | |||
_ = getToken() | |||
goto sendjob | |||
} | |||
jsonstr, _ := json.Marshal(result) | |||
log.Info("GetUserImages resp:", string(jsonstr)) | |||
if result.ErrorCode != 0 { | |||
log.Error("GetUserImages failed(%d): %s", result.ErrorCode, result.ErrorMsg) | |||
return &result, fmt.Errorf("GetUserImages failed(%d): %s", result.ErrorCode, result.ErrorMsg) | |||
} | |||
return &result, nil | |||
} | |||
func GetTrainJobLog(jobID string, nodeId ...int) (string, error) { | |||
checkSetting() | |||
client := getRestyClient() | |||
@@ -1154,6 +1154,14 @@ type CommitImageParams struct { | |||
UID int64 | |||
Place string | |||
Type int | |||
Framework string | |||
FrameworkVersion string | |||
CudaVersion string | |||
PythonVersion string | |||
OperationSystem string | |||
OperationSystemVersion string | |||
ThirdPackages string | |||
ComputeResource string | |||
} | |||
type CommitImageResult struct { | |||
@@ -2038,17 +2046,14 @@ type GrampusResourceQueue struct { | |||
} | |||
type AICenterImage struct { | |||
AICenterID string `json:"aiCenterId"` | |||
ImageUrl string `json:"imageUrl"` | |||
} | |||
type GrampusImage struct { | |||
CreatedAt int64 `json:"createdAt"` | |||
UpdatedAt int64 `json:"updatedAt"` | |||
ID string `json:"id"` | |||
Name string `json:"name"` | |||
ProcessorType string `json:"processorType"` | |||
AICenterImage []AICenterImage `json:"aiCenterImages"` | |||
TrainType string `json:"trainType"` | |||
AICenterImage []AiCenterImage `json:"aiCenterImages"` | |||
} | |||
type GetGrampusImagesResult struct { | |||
@@ -1,12 +1,15 @@ | |||
package models | |||
import ( | |||
"database/sql/driver" | |||
"encoding/json" | |||
"fmt" | |||
"strings" | |||
"unicode/utf8" | |||
"xorm.io/builder" | |||
"code.gitea.io/gitea/modules/log" | |||
"code.gitea.io/gitea/modules/timeutil" | |||
) | |||
@@ -43,10 +46,43 @@ type Image struct { | |||
ApplyStatus ApplyStatus `xorm:"DEFAULT 1" json:"apply_status"` | |||
Message string `xorm:"varchar(500)" json:"message"` | |||
UseCount int64 `xorm:"NOT NULL DEFAULT 0" json:"useCount"` | |||
Framework string `xorm:"varchar(100)" json:"framework" ` | |||
FrameworkVersion string `xorm:"varchar(50)" json:"frameworkVersion" ` | |||
CudaVersion string `xorm:"varchar(50)" json:"cudaVersion" ` | |||
PythonVersion string `xorm:"varchar(50)" json:"pythonVersion" ` | |||
OperationSystem string `xorm:"varchar(100)" json:"operationSystem" ` | |||
OperationSystemVersion string `xorm:"varchar(50)" json:"operationSystemVersion" ` | |||
ThirdPackages string `xorm:"varchar(1000)" json:"thirdPackages" ` | |||
AiCenterImages `gorm:"type:json;comment:智算中心镜像"` | |||
GrampusBaseImage int `xorm:"" json:"grampusBaseImage"` //为1,表示分中心基础镜像 | |||
TrainType string `xorm:"varchar(30)" json:"trainType"` // 镜像适用调试还是训练 | |||
HuJingId string `xorm:"varchar(50)" json:"huJingId" ` //虎鲸侧镜像ID,用于同步镜像信息 | |||
ProcessorType string `xorm:"varchar(50)" json:"processorType" ` //虎鲸侧资源类型,用于同步镜像信息 | |||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created" json:"createdUnix"` | |||
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated" json:"updatedUnix"` | |||
} | |||
type AiCenterImages []AiCenterImage | |||
type AiCenterImage struct { | |||
AiCenterId string `json:"aiCenterId"` | |||
ImageUrl string `json:"imageUrl"` | |||
ImageId string `json:"imageId"` | |||
} | |||
func (r AiCenterImages) Value() (driver.Value, error) { | |||
return json.Marshal(r) | |||
} | |||
func (r *AiCenterImages) Scan(input interface{}) error { | |||
switch v := input.(type) { | |||
case []byte: | |||
return json.Unmarshal(input.([]byte), r) | |||
default: | |||
return fmt.Errorf("cannot Scan() from: %#v", v) | |||
} | |||
} | |||
type ImageList []*Image | |||
type ImageStar struct { | |||
@@ -64,10 +100,19 @@ type ImageTopic struct { | |||
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` | |||
} | |||
type ImageVersionList struct { | |||
} | |||
type ImageTopicRelation struct { | |||
ImageID int64 `xorm:"UNIQUE(s)"` | |||
TopicID int64 `xorm:"UNIQUE(s)"` | |||
} | |||
type SearchAvailableValueOptions struct { | |||
Column string | |||
Framework string | |||
FrameworkVersion string | |||
PythonVersion string | |||
} | |||
type SearchImageOptions struct { | |||
Keyword string | |||
@@ -82,6 +127,16 @@ type SearchImageOptions struct { | |||
Topics string | |||
ApplyStatus int | |||
CloudbrainType int | |||
Framework string | |||
FrameworkVersion string | |||
CudaVersion string | |||
PythonVersion string | |||
OperationSystem string | |||
OperationSystemVersion string | |||
ThirdPackages string | |||
AiCenterId string | |||
TrainType string | |||
ComputeResource string | |||
ListOptions | |||
SearchOrderBy | |||
} | |||
@@ -119,6 +174,14 @@ type CommitGrampusImageParams struct { | |||
UID int64 | |||
Place string | |||
Type int | |||
Framework string | |||
FrameworkVersion string | |||
CudaVersion string | |||
PythonVersion string | |||
OperationSystem string | |||
OperationSystemVersion string | |||
ThirdPackages string | |||
ComputeResource string | |||
} | |||
type CommitGrampusImageResult struct { | |||
@@ -231,6 +294,15 @@ func GetImageByTag(tag string) (*Image, error) { | |||
return image, nil | |||
} | |||
func GetImageByComputeResource(computeResource string) ([]Image, error) { | |||
images := make([]Image, 0) | |||
err := x.Where("status=1 and compute_resource=?", computeResource).Find(&images) | |||
if err != nil { | |||
return nil, err | |||
} | |||
return images, nil | |||
} | |||
func GetImageByTagAndCloudbrainType(tag string, cloudbrainType int) (*Image, error) { | |||
image := &Image{Tag: tag} | |||
has, err := x. | |||
@@ -403,6 +475,35 @@ func removeTopicFromImage(e Engine, imageId int64, topic *ImageTopic) error { | |||
return nil | |||
} | |||
func GetImageAvailableColumnValues(opts *SearchAvailableValueOptions) []string { | |||
var cond = builder.NewCond() | |||
if opts.Framework != "" { | |||
cond = cond.And(builder.Eq{"framework": opts.Framework}) | |||
} | |||
if opts.FrameworkVersion != "" { | |||
cond = cond.And(builder.Eq{"framework_version": opts.FrameworkVersion}) | |||
} | |||
if opts.PythonVersion != "" { | |||
cond = cond.And(builder.Eq{"python_version": opts.PythonVersion}) | |||
} | |||
cond = cond.And(builder.NotNull{opts.Column}) | |||
var columnValues []string | |||
var re []string | |||
_ = x.Table("image").Where(cond).Distinct(opts.Column).Desc(opts.Column).Cols(opts.Column).Find(&columnValues) | |||
if columnValues == nil { | |||
return []string{} | |||
} else { | |||
for _, tmp := range columnValues { | |||
if tmp != "" { | |||
re = append(re, tmp) | |||
} | |||
} | |||
} | |||
return re | |||
} | |||
func SearchImage(opts *SearchImageOptions) (ImageList, int64, error) { | |||
cond := SearchImageCondition(opts) | |||
return SearchImageByCondition(opts, cond) | |||
@@ -431,6 +532,13 @@ func SearchImageCondition(opts *SearchImageOptions) builder.Cond { | |||
likes = likes.Or(builder.Like{"LOWER(description)", strings.ToLower(v)}) | |||
likes = likes.Or(builder.Like{"LOWER(third_packages)", strings.ToLower(v)}) | |||
likes = likes.Or(builder.Like{"LOWER(CONCAT(framework,framework_version))", strings.ToLower(v)}) | |||
likes = likes.Or(builder.Like{"LOWER(CONCAT('cuda',cuda_version))", strings.ToLower(v)}) | |||
likes = likes.Or(builder.Like{"LOWER(CONCAT('python',python_version))", strings.ToLower(v)}) | |||
likes = likes.Or(builder.Like{"LOWER(CONCAT(operation_system,operation_system_version))", strings.ToLower(v)}) | |||
} | |||
keywordCond = keywordCond.Or(likes) | |||
@@ -473,6 +581,48 @@ func SearchImageCondition(opts *SearchImageOptions) builder.Cond { | |||
if opts.Status >= 0 { | |||
cond = cond.And(builder.Eq{"status": opts.Status}) | |||
} | |||
if opts.Framework != "" { | |||
cond = cond.And(builder.Eq{"framework": opts.Framework}) | |||
} | |||
if opts.FrameworkVersion != "" { | |||
cond = cond.And(builder.Eq{"framework_version": opts.FrameworkVersion}) | |||
} | |||
if opts.CudaVersion != "" { | |||
cond = cond.And(builder.Eq{"cuda_version": opts.CudaVersion}) | |||
} | |||
if opts.PythonVersion != "" { | |||
cond = cond.And(builder.Eq{"python_version": opts.PythonVersion}) | |||
} | |||
if opts.OperationSystem != "" { | |||
cond = cond.And(builder.Eq{"operation_system": opts.OperationSystem}) | |||
} | |||
if opts.OperationSystemVersion != "" { | |||
cond = cond.And(builder.Eq{"operation_system_version": opts.OperationSystemVersion}) | |||
} | |||
if opts.AiCenterId != "" { | |||
cond = cond.And(builder.Like{"ai_center_images", "\"aiCenterId\":\"" + opts.AiCenterId + "\""}) | |||
} | |||
if opts.TrainType != "" { | |||
var orCond = builder.NewCond() | |||
orCond = orCond.Or(builder.Eq{"train_type": opts.TrainType}) | |||
orCond = orCond.Or(builder.Eq{"train_type": ""}) | |||
log.Info("opts.TrainType=" + opts.TrainType) | |||
cond = cond.And(orCond) | |||
} | |||
if opts.ComputeResource != "" { | |||
cond = cond.And(builder.Eq{"compute_resource": opts.ComputeResource}) | |||
} | |||
var third_likes, isValid = builder.NewCond(), false | |||
for _, v := range strings.Split(opts.ThirdPackages, " ") { | |||
if v != "" { | |||
third_likes = third_likes.And(builder.Like{"LOWER(third_packages)", strings.ToLower(v)}) | |||
isValid = true | |||
} | |||
} | |||
if isValid { | |||
cond = cond.And(third_likes) | |||
} | |||
if opts.IncludeStarByMe { | |||
@@ -579,7 +729,8 @@ func CreateLocalImage(image *Image) error { | |||
func UpdateLocalImage(image *Image) error { | |||
_, err := x.ID(image.ID).Cols("description", "is_private", "status", "message", "apply_status").Update(image) | |||
_, err := x.ID(image.ID).Cols("description", "is_private", "status", "message", "apply_status", "framework", "framework_version", | |||
"cuda_version", "python_version", "operation_system", "operation_system_version,third_packages").Update(image) | |||
return err | |||
} | |||
@@ -591,7 +742,7 @@ func UpdateLocalImageStatus(image *Image) error { | |||
func UpdateLocalImageStatusAndPlace(image *Image) error { | |||
_, err := x.ID(image.ID).Cols("status", "place").Update(image) | |||
_, err := x.ID(image.ID).Cols("status", "place", "ai_center_images").Update(image) | |||
return err | |||
} | |||
@@ -672,3 +823,73 @@ func GetRecommondType(recommond bool) int { | |||
} | |||
} | |||
func GetGrampusAllBaseImage() (ImageList, error) { | |||
var cond = builder.NewCond() | |||
cond = cond.And(builder.Eq{"grampus_base_image": 1}) | |||
images := make(ImageList, 0, 100) | |||
err := x.Table("image").Where(cond).Find(&images) | |||
if err != nil { | |||
return nil, err | |||
} | |||
return images, nil | |||
} | |||
func getComputeResourceByProcessType(processType string) string { | |||
tail := strings.LastIndex(processType, "/") | |||
if tail > 0 { | |||
return strings.ToUpper(processType[tail+1:]) | |||
} | |||
return strings.ToUpper(processType) | |||
} | |||
func SyncGrampusAllBaseImageToDb(insertList []GrampusImage, updateList []GrampusImage, updateDbList []*Image, deleteList []*Image, doerId int64) error { | |||
for _, tmp := range insertList { | |||
log.Info("insert image,image name=" + tmp.Name) | |||
insObj := &Image{ | |||
Type: 5, | |||
CloudbrainType: 2, | |||
UID: doerId, | |||
IsPrivate: false, | |||
Tag: tmp.Name, | |||
ProcessorType: tmp.ProcessorType, | |||
ComputeResource: getComputeResourceByProcessType(tmp.ProcessorType), | |||
Status: 1, | |||
GrampusBaseImage: 1, | |||
TrainType: tmp.TrainType, | |||
HuJingId: tmp.ID, | |||
AiCenterImages: tmp.AICenterImage, | |||
} | |||
if insObj.ComputeResource == "GPU" && tmp.AICenterImage != nil && len(tmp.AICenterImage) > 0 { | |||
insObj.Place = tmp.AICenterImage[0].ImageUrl | |||
} | |||
x.Insert(insObj) | |||
} | |||
for _, tmp := range deleteList { | |||
log.Info("delete image,image name=" + tmp.Tag) | |||
x.Delete(tmp) | |||
} | |||
for i, tmp := range updateList { | |||
log.Info("update image,image name=" + tmp.Name) | |||
updateDbList[i].AiCenterImages = tmp.AICenterImage | |||
updateDbList[i].Tag = tmp.Name | |||
x.ID(updateDbList[i].ID).Cols("ai_center_images", "tag").Update(updateDbList[i]) | |||
} | |||
return nil | |||
} | |||
func GetGrampusSrcAllBaseImage(srcImageUrl string) (ImageList, error) { | |||
var cond = builder.NewCond() | |||
cond = cond.And(builder.Eq{"grampus_base_image": 1}) | |||
cond = cond.And(builder.Eq{"train_type": "Notebook"}) | |||
cond = cond.And(builder.Like{"ai_center_images", "\"imageUrl\":\"" + srcImageUrl + "\""}) | |||
images := make(ImageList, 0, 10) | |||
err := x.Table("image").Where(cond).Find(&images) | |||
if err != nil { | |||
return nil, err | |||
} | |||
return images, nil | |||
} |
@@ -195,6 +195,7 @@ func init() { | |||
new(UserBusinessAnalysisYesterday), | |||
new(UserBusinessAnalysisLastWeek), | |||
new(UserLoginLog), | |||
new(UserLoginActionLog), | |||
new(UserOtherInfo), | |||
new(UserMetrics), | |||
new(UserAnalysisPara), | |||
@@ -589,3 +589,14 @@ func QueryUserAnnualReport(userId int64) *UserSummaryCurrentYear { | |||
} | |||
return nil | |||
} | |||
func GetLastModifyTime() string { | |||
statictisSess := xStatistic.NewSession() | |||
defer statictisSess.Close() | |||
userBusinessAnalysisLastMonth := &UserBusinessAnalysisLastMonth{} | |||
err := statictisSess.Select("*").Table(new(UserBusinessAnalysisLastMonth)).Limit(1, 0).Find(userBusinessAnalysisLastMonth) | |||
if err == nil { | |||
return userBusinessAnalysisLastMonth.DataDate | |||
} | |||
return "" | |||
} |
@@ -41,24 +41,6 @@ func (ulist UserBusinessAnalysisList) Less(i, j int) bool { | |||
return ulist[i].ID > ulist[j].ID | |||
} | |||
func getLastCountDate() int64 { | |||
statictisSess := xStatistic.NewSession() | |||
defer statictisSess.Close() | |||
statictisSess.Limit(1, 0) | |||
userBusinessAnalysisList := make([]*UserBusinessAnalysis, 0) | |||
if err := statictisSess.Table("user_business_analysis").OrderBy("count_date desc").Limit(1, 0). | |||
Find(&userBusinessAnalysisList); err == nil { | |||
for _, userRecord := range userBusinessAnalysisList { | |||
return userRecord.CountDate - 10000 | |||
} | |||
} else { | |||
log.Info("query error." + err.Error()) | |||
} | |||
currentTimeNow := time.Now() | |||
pageStartTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 0, 0, 0, 0, currentTimeNow.Location()) | |||
return pageStartTime.Unix() | |||
} | |||
func QueryMetricsPage(start int64, end int64) ([]*UserMetrics, int64) { | |||
statictisSess := xStatistic.NewSession() | |||
@@ -633,6 +615,8 @@ func refreshUserStaticTable(wikiCountMap map[string]int, tableName string, pageS | |||
CreateRepoCountMap, _, _, _ := queryUserCreateRepo(start_unix, end_unix) | |||
LoginCountMap := queryLoginCount(start_unix, end_unix) | |||
LoginActionCountMap := queryLoginActionCount(start_unix, end_unix) | |||
OpenIIndexMap := queryUserRepoOpenIIndex(startTime.Unix(), end_unix) | |||
CloudBrainTaskMap, CloudBrainTaskItemMap, _ := queryCloudBrainTask(start_unix, end_unix) | |||
AiModelManageMap := queryUserModel(start_unix, end_unix) | |||
@@ -695,6 +679,7 @@ func refreshUserStaticTable(wikiCountMap map[string]int, tableName string, pageS | |||
dateRecordAll.EncyclopediasCount = getMapKeyStringValue(dateRecordAll.Name, wikiCountMap) | |||
dateRecordAll.CreateRepoCount = getMapValue(dateRecordAll.ID, CreateRepoCountMap) | |||
dateRecordAll.LoginCount = getMapValue(dateRecordAll.ID, LoginCountMap) | |||
dateRecordAll.LoginActionCount = getMapValue(dateRecordAll.ID, LoginActionCountMap) | |||
if _, ok := OpenIIndexMap[dateRecordAll.ID]; !ok { | |||
dateRecordAll.OpenIIndex = 0 | |||
@@ -720,6 +705,7 @@ func refreshUserStaticTable(wikiCountMap map[string]int, tableName string, pageS | |||
dateRecordAll.RecommendImage = getMapValue(dateRecordAll.ID, RecommendImage) | |||
dateRecordAll.InvitationUserNum = getMapValue(dateRecordAll.ID, InvitationMap) | |||
dateRecordAll.UserIndexPrimitive = getUserIndexFromAnalysisAll(dateRecordAll, ParaWeight) | |||
userIndexMap[dateRecordAll.ID] = dateRecordAll.UserIndexPrimitive | |||
if maxUserIndex < dateRecordAll.UserIndexPrimitive { | |||
maxUserIndex = dateRecordAll.UserIndexPrimitive | |||
@@ -933,7 +919,7 @@ func insertTable(dateRecords []UserBusinessAnalysisAll, tableName string, static | |||
insertBatchSql := "INSERT INTO public." + tableName + | |||
"(id, count_date, code_merge_count, commit_count, issue_count, comment_count, focus_repo_count, star_repo_count, watched_count, gitea_age_month, commit_code_size, commit_dataset_size, " + | |||
"commit_model_count, solve_issue_count, encyclopedias_count, regist_date, create_repo_count, login_count, open_i_index, email, name, data_date,cloud_brain_task_num,gpu_debug_job,npu_debug_job,gpu_train_job,npu_train_job,npu_inference_job,gpu_bench_mark_job,cloud_brain_run_time,commit_dataset_num,user_index,user_location,focus_other_user,collect_dataset,collected_dataset,recommend_dataset,collect_image,collected_image,recommend_image,user_index_primitive,phone,invitation_user_num,model_convert_count) " + | |||
"commit_model_count, solve_issue_count, encyclopedias_count, regist_date, create_repo_count, login_count, open_i_index, email, name, data_date,cloud_brain_task_num,gpu_debug_job,npu_debug_job,gpu_train_job,npu_train_job,npu_inference_job,gpu_bench_mark_job,cloud_brain_run_time,commit_dataset_num,user_index,user_location,focus_other_user,collect_dataset,collected_dataset,recommend_dataset,collect_image,collected_image,recommend_image,user_index_primitive,phone,invitation_user_num,model_convert_count,login_action_count) " + | |||
"VALUES" | |||
for i, record := range dateRecords { | |||
@@ -942,7 +928,7 @@ func insertTable(dateRecords []UserBusinessAnalysisAll, tableName string, static | |||
", " + fmt.Sprint(record.WatchedCount) + ", " + fmt.Sprint(record.GiteaAgeMonth) + ", " + fmt.Sprint(record.CommitCodeSize) + ", " + fmt.Sprint(record.CommitDatasetSize) + | |||
", " + fmt.Sprint(record.CommitModelCount) + ", " + fmt.Sprint(record.SolveIssueCount) + ", " + fmt.Sprint(record.EncyclopediasCount) + ", " + fmt.Sprint(record.RegistDate) + | |||
", " + fmt.Sprint(record.CreateRepoCount) + ", " + fmt.Sprint(record.LoginCount) + ", " + fmt.Sprint(record.OpenIIndex) + ", '" + record.Email + "', '" + record.Name + "', '" + record.DataDate + "'," + fmt.Sprint(record.CloudBrainTaskNum) + "," + fmt.Sprint(record.GpuDebugJob) + "," + fmt.Sprint(record.NpuDebugJob) + "," + fmt.Sprint(record.GpuTrainJob) + "," + fmt.Sprint(record.NpuTrainJob) + "," + fmt.Sprint(record.NpuInferenceJob) + "," + fmt.Sprint(record.GpuBenchMarkJob) + "," + fmt.Sprint(record.CloudBrainRunTime) + "," + fmt.Sprint(record.CommitDatasetNum) + "," + fmt.Sprint(record.UserIndex) + ",'" + record.UserLocation + "'," + | |||
fmt.Sprint(record.FocusOtherUser) + "," + fmt.Sprint(record.CollectDataset) + "," + fmt.Sprint(record.CollectedDataset) + "," + fmt.Sprint(record.RecommendDataset) + "," + fmt.Sprint(record.CollectImage) + "," + fmt.Sprint(record.CollectedImage) + "," + fmt.Sprint(record.RecommendImage) + "," + fmt.Sprint(record.UserIndexPrimitive) + ",'" + record.Phone + "'" + "," + fmt.Sprint(record.InvitationUserNum) + "," + fmt.Sprint(record.ModelConvertCount) + ")" | |||
fmt.Sprint(record.FocusOtherUser) + "," + fmt.Sprint(record.CollectDataset) + "," + fmt.Sprint(record.CollectedDataset) + "," + fmt.Sprint(record.RecommendDataset) + "," + fmt.Sprint(record.CollectImage) + "," + fmt.Sprint(record.CollectedImage) + "," + fmt.Sprint(record.RecommendImage) + "," + fmt.Sprint(record.UserIndexPrimitive) + ",'" + record.Phone + "'" + "," + fmt.Sprint(record.InvitationUserNum) + "," + fmt.Sprint(record.ModelConvertCount) + "," + fmt.Sprint(record.LoginActionCount) + ")" | |||
if i < (len(dateRecords) - 1) { | |||
insertBatchSql += "," | |||
} | |||
@@ -2222,6 +2208,40 @@ func queryLoginCount(start_unix int64, end_unix int64) map[int64]int { | |||
return resultMap | |||
} | |||
func queryLoginActionCount(start_unix int64, end_unix int64) map[int64]int { | |||
statictisSess := xStatistic.NewSession() | |||
defer statictisSess.Close() | |||
resultMap := make(map[int64]int) | |||
cond := "created_unix>=" + fmt.Sprint(start_unix) + " and created_unix<=" + fmt.Sprint(end_unix) | |||
count, err := statictisSess.Where(cond).Count(new(UserLoginActionLog)) | |||
if err != nil { | |||
log.Info("query UserLoginActionLog error. return.") | |||
return resultMap | |||
} | |||
var indexTotal int64 | |||
indexTotal = 0 | |||
for { | |||
statictisSess.Select("id,u_id").Table("user_login_action_log").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal)) | |||
userLoginActionLogList := make([]*UserLoginActionLog, 0) | |||
statictisSess.Find(&userLoginActionLogList) | |||
log.Info("query user login action size=" + fmt.Sprint(len(userLoginActionLogList))) | |||
for _, loginRecord := range userLoginActionLogList { | |||
if _, ok := resultMap[loginRecord.UId]; !ok { | |||
resultMap[loginRecord.UId] = 1 | |||
} else { | |||
resultMap[loginRecord.UId] += 1 | |||
} | |||
} | |||
indexTotal += PAGE_SIZE | |||
if indexTotal >= count { | |||
break | |||
} | |||
} | |||
log.Info("user login action size=" + fmt.Sprint(len(resultMap))) | |||
return resultMap | |||
} | |||
func queryUserModel(start_unix int64, end_unix int64) map[int64]int { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
@@ -35,7 +35,7 @@ type UserBusinessAnalysisCurrentYear struct { | |||
RegistDate timeutil.TimeStamp `xorm:"NOT NULL"` | |||
//repo | |||
CreateRepoCount int `xorm:"NOT NULL DEFAULT 0"` | |||
//login count, from elk | |||
//login count | |||
LoginCount int `xorm:"NOT NULL DEFAULT 0"` | |||
//openi index | |||
OpenIIndex float64 `xorm:"NOT NULL DEFAULT 0"` | |||
@@ -69,6 +69,8 @@ type UserBusinessAnalysisCurrentYear struct { | |||
Phone string `xorm:"NULL"` | |||
InvitationUserNum int `xorm:"NOT NULL DEFAULT 0"` | |||
ModelConvertCount int `xorm:"NOT NULL DEFAULT 0"` | |||
LoginActionCount int `xorm:"NOT NULL DEFAULT 0"` | |||
} | |||
type UserBusinessAnalysisLast30Day struct { | |||
@@ -138,6 +140,8 @@ type UserBusinessAnalysisLast30Day struct { | |||
Phone string `xorm:"NULL"` | |||
InvitationUserNum int `xorm:"NOT NULL DEFAULT 0"` | |||
ModelConvertCount int `xorm:"NOT NULL DEFAULT 0"` | |||
LoginActionCount int `xorm:"NOT NULL DEFAULT 0"` | |||
} | |||
type UserBusinessAnalysisLastMonth struct { | |||
@@ -207,6 +211,8 @@ type UserBusinessAnalysisLastMonth struct { | |||
Phone string `xorm:"NULL"` | |||
InvitationUserNum int `xorm:"NOT NULL DEFAULT 0"` | |||
ModelConvertCount int `xorm:"NOT NULL DEFAULT 0"` | |||
LoginActionCount int `xorm:"NOT NULL DEFAULT 0"` | |||
} | |||
type UserBusinessAnalysisCurrentMonth struct { | |||
@@ -276,6 +282,8 @@ type UserBusinessAnalysisCurrentMonth struct { | |||
Phone string `xorm:"NULL"` | |||
InvitationUserNum int `xorm:"NOT NULL DEFAULT 0"` | |||
ModelConvertCount int `xorm:"NOT NULL DEFAULT 0"` | |||
LoginActionCount int `xorm:"NOT NULL DEFAULT 0"` | |||
} | |||
type UserBusinessAnalysisCurrentWeek struct { | |||
@@ -346,6 +354,8 @@ type UserBusinessAnalysisCurrentWeek struct { | |||
Phone string `xorm:"NULL"` | |||
InvitationUserNum int `xorm:"NOT NULL DEFAULT 0"` | |||
ModelConvertCount int `xorm:"NOT NULL DEFAULT 0"` | |||
LoginActionCount int `xorm:"NOT NULL DEFAULT 0"` | |||
} | |||
type UserBusinessAnalysisYesterday struct { | |||
@@ -416,6 +426,8 @@ type UserBusinessAnalysisYesterday struct { | |||
Phone string `xorm:"NULL"` | |||
InvitationUserNum int `xorm:"NOT NULL DEFAULT 0"` | |||
ModelConvertCount int `xorm:"NOT NULL DEFAULT 0"` | |||
LoginActionCount int `xorm:"NOT NULL DEFAULT 0"` | |||
} | |||
type UserBusinessAnalysisLastWeek struct { | |||
@@ -486,6 +498,8 @@ type UserBusinessAnalysisLastWeek struct { | |||
Phone string `xorm:"NULL"` | |||
InvitationUserNum int `xorm:"NOT NULL DEFAULT 0"` | |||
ModelConvertCount int `xorm:"NOT NULL DEFAULT 0"` | |||
LoginActionCount int `xorm:"NOT NULL DEFAULT 0"` | |||
} | |||
type UserAnalysisPara struct { | |||
@@ -603,6 +617,8 @@ type UserBusinessAnalysisAll struct { | |||
Phone string `xorm:"NULL"` | |||
InvitationUserNum int `xorm:"NOT NULL DEFAULT 0"` | |||
ModelConvertCount int `xorm:"NOT NULL DEFAULT 0"` | |||
LoginActionCount int `xorm:"NOT NULL DEFAULT 0"` | |||
} | |||
type UserBusinessAnalysis struct { | |||
@@ -692,4 +708,6 @@ type UserBusinessAnalysis struct { | |||
Phone string `xorm:"NULL"` | |||
InvitationUserNum int `xorm:"NOT NULL DEFAULT 0"` | |||
ModelConvertCount int `xorm:"NOT NULL DEFAULT 0"` | |||
LoginActionCount int `xorm:"NOT NULL DEFAULT 0"` | |||
} |
@@ -0,0 +1,20 @@ | |||
package models | |||
import ( | |||
"code.gitea.io/gitea/modules/timeutil" | |||
) | |||
//用户活跃信息表 | |||
type UserLoginActionLog struct { | |||
ID int64 `xorm:"pk autoincr"` | |||
UId int64 `xorm:"NOT NULL"` | |||
CreatedUnix timeutil.TimeStamp `xorm:"created"` | |||
} | |||
func SaveLoginActionToDb(uid int64) { | |||
statictisSess := xStatistic.NewSession() | |||
defer statictisSess.Close() | |||
var dateRecord UserLoginActionLog | |||
dateRecord.UId = uid | |||
statictisSess.Insert(&dateRecord) | |||
} |
@@ -41,6 +41,14 @@ type CommitImageCloudBrainForm struct { | |||
Tag string `form:"tag" binding:"Required;MaxSize(100)" ` | |||
IsPrivate bool `form:"isPrivate" binding:"Required"` | |||
Topics string `form:"topics"` | |||
Framework string `form:"framework" binding:"Required"` | |||
FrameworkVersion string `form:"frameworkVersion"` | |||
CudaVersion string `form:"cudaVersion" binding:"Required"` | |||
PythonVersion string `form:"pythonVersion" binding:"Required"` | |||
OperationSystem string `form:"operationSystem"` | |||
OperationSystemVersion string `form:"operationSystemVersion"` | |||
ThirdPackages string `form:"thirdPackages"` | |||
ComputeResource string `form:"computeResource"` | |||
} | |||
type CommitImageGrampusForm struct { | |||
Description string `form:"description" binding:"Required"` | |||
@@ -48,6 +56,14 @@ type CommitImageGrampusForm struct { | |||
Tag string `form:"tag" binding:"Required;MaxSize(50)" ` | |||
IsPrivate bool `form:"isPrivate" binding:"Required"` | |||
Topics string `form:"topics"` | |||
Framework string `form:"framework" binding:"Required"` | |||
FrameworkVersion string `form:"frameworkVersion"` | |||
CudaVersion string `form:"cudaVersion" binding:"Required"` | |||
PythonVersion string `form:"pythonVersion" binding:"Required"` | |||
OperationSystem string `form:"operationSystem"` | |||
OperationSystemVersion string `form:"operationSystemVersion"` | |||
ThirdPackages string `form:"thirdPackages"` | |||
ComputeResource string `form:"computeResource"` | |||
} | |||
type CommitAdminImageCloudBrainForm struct { | |||
@@ -58,12 +74,27 @@ type CommitAdminImageCloudBrainForm struct { | |||
Topics string `form:"topics"` | |||
Place string `form:"place" binding:"Required"` | |||
IsRecommend bool `form:"isRecommend" binding:"Required"` | |||
Framework string `form:"framework" binding:"Required"` | |||
FrameworkVersion string `form:"frameworkVersion" binding:"Required"` | |||
CudaVersion string `form:"cudaVersion" binding:"Required"` | |||
PythonVersion string `form:"pythonVersion" binding:"Required"` | |||
OperationSystem string `form:"operationSystem"` | |||
OperationSystemVersion string `form:"operationSystemVersion"` | |||
ThirdPackages string `form:"thirdPackages"` | |||
ComputeResource string `form:"computeResource"` | |||
} | |||
type EditImageCloudBrainForm struct { | |||
ID int64 `form:"id" binding:"Required"` | |||
Description string `form:"description" binding:"Required"` | |||
Topics string `form:"topics"` | |||
Framework string `form:"framework" binding:"Required"` | |||
FrameworkVersion string `form:"frameworkVersion" binding:"Required"` | |||
CudaVersion string `form:"cudaVersion" binding:"Required"` | |||
PythonVersion string `form:"pythonVersion" binding:"Required"` | |||
OperationSystem string `form:"operationSystem"` | |||
OperationSystemVersion string `form:"operationSystemVersion"` | |||
ThirdPackages string `form:"thirdPackages"` | |||
} | |||
type ReviewImageForm struct { | |||
@@ -359,6 +359,13 @@ sendjob: | |||
Place: setting.Cloudbrain.ImageURLPrefix + imageTag, | |||
Status: models.IMAGE_STATUS_COMMIT, | |||
ApplyStatus: models.NoneApply, | |||
Framework: params.Framework, | |||
FrameworkVersion: params.FrameworkVersion, | |||
CudaVersion: params.CudaVersion, | |||
PythonVersion: params.PythonVersion, | |||
OperationSystem: params.OperationSystem, | |||
OperationSystemVersion: params.OperationSystemVersion, | |||
ThirdPackages: params.ThirdPackages, | |||
} | |||
err = models.WithTx(func(ctx models.DBContext) error { | |||
@@ -367,6 +374,13 @@ sendjob: | |||
dbImage.IsPrivate = params.IsPrivate | |||
dbImage.Description = params.ImageDescription | |||
dbImage.Status = models.IMAGE_STATUS_COMMIT | |||
dbImage.Framework = params.Framework | |||
dbImage.FrameworkVersion = params.FrameworkVersion | |||
dbImage.CudaVersion = params.CudaVersion | |||
dbImage.PythonVersion = params.PythonVersion | |||
dbImage.OperationSystem = params.OperationSystem | |||
dbImage.OperationSystemVersion = params.OperationSystemVersion | |||
dbImage.ThirdPackages = params.ThirdPackages | |||
image = *dbImage | |||
if err := models.UpdateLocalImage(dbImage); err != nil { | |||
log.Error("Failed to update image record.", err) | |||
@@ -415,6 +429,14 @@ func CommitAdminImage(params models.CommitImageParams, doer *models.User) error | |||
Status: models.IMAGE_STATUS_SUCCESS, | |||
Type: params.Type, | |||
ApplyStatus: models.NoneApply, | |||
Framework: params.Framework, | |||
FrameworkVersion: params.FrameworkVersion, | |||
CudaVersion: params.CudaVersion, | |||
PythonVersion: params.PythonVersion, | |||
OperationSystem: params.OperationSystem, | |||
OperationSystemVersion: params.OperationSystemVersion, | |||
ThirdPackages: params.ThirdPackages, | |||
ComputeResource: params.ComputeResource, | |||
} | |||
err = models.WithTx(func(ctx models.DBContext) error { | |||
@@ -307,6 +307,7 @@ func Contexter() macaron.Handler { | |||
if ctx.User != nil { | |||
ctx.IsSigned = true | |||
toCache(ctx) | |||
ctx.Data["IsSigned"] = ctx.IsSigned | |||
ctx.Data["SignedUser"] = ctx.User | |||
ctx.Data["SignedUserID"] = ctx.User.ID | |||
@@ -0,0 +1,42 @@ | |||
package context | |||
import ( | |||
"fmt" | |||
"sync" | |||
"time" | |||
"code.gitea.io/gitea/models" | |||
"code.gitea.io/gitea/modules/log" | |||
) | |||
var userActionMap sync.Map | |||
var userChannel = make(chan int64, 10000) | |||
func UserActionChannelInit() { | |||
go consumerUserAction(userChannel) | |||
} | |||
func UserActionMapClear() { | |||
userActionMap.Range(func(key, value any) bool { | |||
userActionMap.Delete(key) | |||
return true | |||
}) | |||
} | |||
func toCache(ctx *Context) { | |||
if ctx.User != nil { | |||
_, ok := userActionMap.Load(ctx.User.ID) | |||
if !ok { | |||
log.Info("add user uid to login action db. uid=" + fmt.Sprint(ctx.User.ID)) | |||
userActionMap.Store(ctx.User.ID, time.Now()) | |||
userChannel <- ctx.User.ID | |||
} | |||
} | |||
} | |||
func consumerUserAction(in <-chan int64) { | |||
for uid := range in { | |||
models.SaveLoginActionToDb(uid) | |||
} | |||
} |
@@ -32,6 +32,7 @@ const ( | |||
urlGetResourceSpecs = urlOpenApiV1 + "resourcespec" | |||
urlGetAiCenter = urlOpenApiV1 + "sharescreen/aicenter" | |||
urlGetImages = urlOpenApiV1 + "image" | |||
urlDelImages = urlOpenApiV1 + "delimage" | |||
urlNotebookJob = urlOpenApiV1 + "notebook" | |||
errorIllegalToken = 1005 | |||
@@ -268,12 +269,10 @@ func GetImages(processorType string, jobType string) (*models.GetGrampusImagesRe | |||
var result models.GetGrampusImagesResult | |||
retry := 0 | |||
queryType := "TrainJob" | |||
if jobType == string(models.JobTypeDebug) { | |||
queryType = "Notebook" | |||
} | |||
sendjob: | |||
_, err := client.R(). | |||
SetAuthToken(TOKEN). | |||
@@ -299,6 +298,35 @@ sendjob: | |||
return &result, nil | |||
} | |||
func GetAllBaseImages() (*models.GetGrampusImagesResult, error) { | |||
checkSetting() | |||
client := getRestyClient() | |||
var result models.GetGrampusImagesResult | |||
retry := 0 | |||
sendjob: | |||
_, err := client.R(). | |||
SetAuthToken(TOKEN). | |||
SetResult(&result). | |||
Get(HOST + urlGetImages) | |||
if err != nil { | |||
return nil, fmt.Errorf("resty GetAllBaseImages: %v", err) | |||
} | |||
if result.ErrorCode == errorIllegalToken && retry < 1 { | |||
retry++ | |||
log.Info("retry get token") | |||
_ = getToken() | |||
goto sendjob | |||
} | |||
if result.ErrorCode != 0 { | |||
log.Error("GetAllBaseImages failed(%d): %s", result.ErrorCode, result.ErrorMsg) | |||
return &result, fmt.Errorf("GetImages failed(%d): %s", result.ErrorCode, result.ErrorMsg) | |||
} | |||
return &result, nil | |||
} | |||
func GetTrainJobLog(jobID string, nodeId ...int) (string, error) { | |||
checkSetting() | |||
client := getRestyClient() | |||
@@ -643,7 +671,7 @@ sendjob: | |||
return restartResponse, nil | |||
} | |||
func CommitImage(jobID string, params models.CommitGrampusImageParams, doer *models.User) error { | |||
func CommitImage(jobID, computeResource, aiCenterId string, params models.CommitGrampusImageParams, doer *models.User) error { | |||
imageTag := strings.TrimSpace(params.ImageVersion) | |||
dbImage, err := models.GetImageByTag(imageTag) | |||
@@ -697,6 +725,12 @@ sendjob: | |||
return fmt.Errorf("CommitImage err: imageid is empty. %s", result.ErrorMsg) | |||
} | |||
aiCenterList := make(models.AiCenterImages, 0) | |||
ai := models.AiCenterImage{ | |||
AiCenterId: aiCenterId, | |||
} | |||
aiCenterList = append(aiCenterList, ai) | |||
image := models.Image{ | |||
Type: models.NORMAL_TYPE, | |||
CloudbrainType: params.CloudBrainType, | |||
@@ -707,26 +741,44 @@ sendjob: | |||
ImageID: result.ImageId, | |||
Status: models.IMAGE_STATUS_COMMIT, | |||
ApplyStatus: models.NoneApply, | |||
Framework: params.Framework, | |||
FrameworkVersion: params.FrameworkVersion, | |||
CudaVersion: params.CudaVersion, | |||
PythonVersion: params.PythonVersion, | |||
OperationSystem: params.OperationSystem, | |||
OperationSystemVersion: params.OperationSystemVersion, | |||
ThirdPackages: params.ThirdPackages, | |||
ComputeResource: params.ComputeResource, | |||
GrampusBaseImage: 0, | |||
AiCenterImages: aiCenterList, | |||
} | |||
err = models.WithTx(func(ctx models.DBContext) error { | |||
models.UpdateAutoIncrementIndex() | |||
if dbImage != nil { | |||
dbImage.IsPrivate = params.IsPrivate | |||
dbImage.Description = params.Description | |||
dbImage.Status = models.IMAGE_STATUS_COMMIT | |||
image = *dbImage | |||
if err := models.UpdateLocalImage(dbImage); err != nil { | |||
log.Error("Failed to update image record.", err) | |||
return fmt.Errorf("CommitImage err: %s", res.String()) | |||
} | |||
} else { | |||
// if dbImage != nil { | |||
// dbImage.IsPrivate = params.IsPrivate | |||
// dbImage.Description = params.Description | |||
// dbImage.Status = models.IMAGE_STATUS_COMMIT | |||
// dbImage.Framework = params.Framework | |||
// dbImage.FrameworkVersion = params.FrameworkVersion | |||
// dbImage.CudaVersion = params.CudaVersion | |||
// dbImage.PythonVersion = params.PythonVersion | |||
// dbImage.OperationSystem = params.OperationSystem | |||
// dbImage.OperationSystemVersion = params.OperationSystemVersion | |||
// dbImage.ThirdPackages = params.ThirdPackages | |||
// dbImage.ComputeResource = params.ComputeResource | |||
// image = *dbImage | |||
// if err := models.UpdateLocalImage(dbImage); err != nil { | |||
// log.Error("Failed to update image record.", err) | |||
// return fmt.Errorf("CommitImage err: %s", res.String()) | |||
// } | |||
// } else { | |||
if err := models.CreateLocalImage(&image); err != nil { | |||
log.Error("Failed to insert image record.", err) | |||
return fmt.Errorf("CommitImage err: %s", res.String()) | |||
} | |||
} | |||
//} | |||
if err := models.SaveImageTopics(image.ID, params.Topics...); err != nil { | |||
log.Error("Failed to insert image record.", err) | |||
return fmt.Errorf("CommitImage err: %s", res.String()) | |||
@@ -789,6 +841,9 @@ func updateImageStatus(image models.Image) { | |||
commitSuccess = true | |||
image.Status = models.IMAGE_STATUS_SUCCESS | |||
image.Place = result.Image.ImageFullAddr | |||
if image.AiCenterImages != nil { | |||
image.AiCenterImages[0].ImageUrl = result.Image.ImageFullAddr | |||
} | |||
models.UpdateLocalImageStatusAndPlace(&image) | |||
return | |||
} | |||
@@ -797,7 +852,6 @@ func updateImageStatus(image models.Image) { | |||
commitSuccess = false | |||
break | |||
} | |||
} | |||
} | |||
if !commitSuccess { | |||
@@ -806,3 +860,32 @@ func updateImageStatus(image models.Image) { | |||
} | |||
} | |||
func DeleteImage(image *models.Image) error { | |||
checkSetting() | |||
client := getRestyClient() | |||
log.Info("start to delete remote image=" + image.ImageID) | |||
var result models.GrampusResult | |||
retry := 0 | |||
sendjob: | |||
res, err := client.R(). | |||
SetAuthToken(TOKEN). | |||
SetResult(&result). | |||
Delete(HOST + urlDelImages + "/" + image.ImageID) | |||
if err != nil { | |||
log.Info("DeleteImage error=" + err.Error()) | |||
return fmt.Errorf("resty DeleteImage: %v", err) | |||
} | |||
if result.ErrorCode == errorIllegalToken && retry < 1 { | |||
retry++ | |||
log.Info("retry get token") | |||
_ = getToken() | |||
goto sendjob | |||
} | |||
if res.StatusCode() != http.StatusOK { | |||
log.Info("res status code=" + fmt.Sprint(res.StatusCode())) | |||
return fmt.Errorf("DeleteImage err: %s", res.String()) | |||
} | |||
return nil | |||
} |
@@ -44,6 +44,10 @@ func Custom(opts *Options) macaron.Handler { | |||
return opts.staticHandler(path.Join(setting.CustomPath, "public")) | |||
} | |||
func CustomJson(opts *Options) macaron.Handler { | |||
return opts.staticHandler(path.Join(setting.CustomPath, "public", "json")) | |||
} | |||
// staticFileSystem implements http.FileSystem interface. | |||
type staticFileSystem struct { | |||
dir *http.Dir | |||
@@ -874,6 +874,7 @@ var ( | |||
ATTACHEMENT_NUM_A_USER_LAST10M int | |||
ATTACHEMENT_SIZE_A_USER int64 //G | |||
ALL_ATTACHEMENT_NUM_SDK int | |||
IGNORE_FLAG string | |||
}{} | |||
LLM_CHAT_API = struct { | |||
@@ -1878,6 +1879,7 @@ func getFlowControlConfig() { | |||
FLOW_CONTROL.ATTACHEMENT_NUM_A_USER_LAST24HOUR = sec.Key("ATTACHEMENT_NUM_A_USER_LAST24HOUR").MustInt(1000) | |||
FLOW_CONTROL.ATTACHEMENT_NUM_A_USER_LAST10M = sec.Key("ATTACHEMENT_NUM_A_USER_LAST10M").MustInt(10) | |||
FLOW_CONTROL.ATTACHEMENT_SIZE_A_USER = sec.Key("ATTACHEMENT_SIZE_A_USER").MustInt64(500) | |||
FLOW_CONTROL.IGNORE_FLAG = sec.Key("IGNORE_FLAG").MustString("") | |||
} | |||
func getModelAppConfig() { | |||
@@ -1,15 +1,16 @@ | |||
package admin | |||
import ( | |||
"net/http" | |||
"strconv" | |||
"strings" | |||
"code.gitea.io/gitea/models" | |||
"code.gitea.io/gitea/modules/base" | |||
"code.gitea.io/gitea/modules/context" | |||
"code.gitea.io/gitea/modules/log" | |||
"code.gitea.io/gitea/routers/response" | |||
"code.gitea.io/gitea/services/cloudbrain/resource" | |||
"net/http" | |||
"strconv" | |||
"strings" | |||
) | |||
const ( | |||
@@ -122,6 +123,10 @@ func SyncGrampusQueue(ctx *context.Context) { | |||
ctx.JSON(http.StatusOK, response.ServerError(err.Error())) | |||
return | |||
} | |||
err = resource.SyncGrampusImage(ctx.User.ID) | |||
if err != nil { | |||
log.Error("sync image error. %v", err) | |||
} | |||
ctx.JSON(http.StatusOK, response.Success()) | |||
} | |||
@@ -709,6 +709,8 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
m.Get("/custom", reqToken(), repo.GetCustomImages) | |||
m.Get("/star", reqToken(), repo.GetStarImages) | |||
m.Get("/npu", reqToken(), repo.GetNpuImages) | |||
m.Get("/availableFilter", reqToken(), | |||
repo.GetAvailableFilerInfo) | |||
}) | |||
@@ -821,6 +823,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
}) | |||
}, operationReq) | |||
m.Get("/query_user_count_time_info", operationReq, repo_ext.QueryUserCountTimeInfo) | |||
m.Get("/query_metrics_current_month", operationReq, repo_ext.QueryUserMetricsCurrentMonth) | |||
m.Get("/query_metrics_current_week", operationReq, repo_ext.QueryUserMetricsCurrentWeek) | |||
m.Get("/query_metrics_current_year", operationReq, repo_ext.QueryUserMetricsCurrentYear) | |||
@@ -1480,6 +1483,11 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
m.Get("/prd/event", authentication.ValidEventSource) | |||
m.Post("/prd/event", authentication.AcceptWechatEvent) | |||
}) | |||
m.Group("/authentication/wechat", func() { | |||
m.Get("/qrCode4Bind", authentication.GetQRCode4Bind) | |||
m.Get("/bindStatus", authentication.GetBindStatus) | |||
m.Post("/unbind", authentication.UnbindWechat) | |||
}, reqToken()) | |||
m.Get("/wechat/material", authentication.GetMaterial) | |||
m.Get("/cloudbrain/get_newest_job", repo.GetNewestJobs) | |||
m.Get("/cloudbrain/get_center_info", repo.GetAICenterInfo) | |||
@@ -6,6 +6,7 @@ import ( | |||
"sync" | |||
"code.gitea.io/gitea/modules/log" | |||
"code.gitea.io/gitea/modules/setting" | |||
"code.gitea.io/gitea/models" | |||
"code.gitea.io/gitea/modules/context" | |||
@@ -74,6 +75,13 @@ func NewMultipart(ctx *context.APIContext) { | |||
}) | |||
return | |||
} | |||
ignore := false | |||
if setting.FLOW_CONTROL.IGNORE_FLAG != "" { | |||
if ctx.Query("IGNORE_FLAG") == setting.FLOW_CONTROL.IGNORE_FLAG { | |||
ignore = true | |||
} | |||
} | |||
if !ignore { | |||
if err := routeRepo.CheckFlowForDatasetSDK(); err != nil { | |||
ctx.JSON(200, map[string]string{ | |||
"result_code": "-1", | |||
@@ -81,6 +89,7 @@ func NewMultipart(ctx *context.APIContext) { | |||
}) | |||
return | |||
} | |||
} | |||
mutex.Lock() | |||
defer mutex.Unlock() | |||
datasetId := ctx.QueryInt64("dataset_id") | |||
@@ -159,7 +168,13 @@ func NewModelMultipart(ctx *context.APIContext) { | |||
}) | |||
return | |||
} | |||
ignore := false | |||
if setting.FLOW_CONTROL.IGNORE_FLAG != "" { | |||
if ctx.Query("IGNORE_FLAG") == setting.FLOW_CONTROL.IGNORE_FLAG { | |||
ignore = true | |||
} | |||
} | |||
if !ignore { | |||
if err := routeRepo.CheckFlowForModelSDK(); err != nil { | |||
ctx.JSON(200, map[string]string{ | |||
"result_code": "-1", | |||
@@ -167,6 +182,7 @@ func NewModelMultipart(ctx *context.APIContext) { | |||
}) | |||
return | |||
} | |||
} | |||
modelMutex.Lock() | |||
defer modelMutex.Unlock() | |||
fileName := ctx.Query("file_name") | |||
@@ -28,6 +28,7 @@ func GetRecommendImages(ctx *context.APIContext) { | |||
IncludeOfficialOnly: true, | |||
Status: models.IMAGE_STATUS_SUCCESS, | |||
CloudbrainType: ctx.QueryInt("cloudbrainType"), | |||
TrainType: ctx.Query("trainType"), | |||
} | |||
routeRepo.GetImages(ctx.Context, &opts) | |||
@@ -59,6 +60,7 @@ func GetCustomImages(ctx *context.APIContext) { | |||
Topics: ctx.Query("topic"), | |||
Status: -1, | |||
CloudbrainType: ctx.QueryInt("cloudbrainType"), | |||
TrainType: "", | |||
} | |||
routeRepo.GetImages(ctx.Context, &opts) | |||
@@ -73,6 +75,7 @@ func GetStarImages(ctx *context.APIContext) { | |||
Topics: ctx.Query("topic"), | |||
Status: models.IMAGE_STATUS_SUCCESS, | |||
CloudbrainType: ctx.QueryInt("cloudbrainType"), | |||
TrainType: "", | |||
} | |||
routeRepo.GetImages(ctx.Context, &opts) | |||
@@ -88,6 +91,31 @@ func GetNpuImages(ctx *context.APIContext) { | |||
} | |||
} | |||
func GetAvailableFilerInfo(ctx *context.APIContext) { | |||
columns := []string{"framework", "framework_version", "python_version", "cuda_version"} | |||
i := ctx.QueryInt("index") | |||
frameWork := ctx.Query("framework") | |||
version := ctx.Query("version") | |||
pythonVersion := ctx.Query("python") | |||
if i < 0 || i >= len(columns) { | |||
i = 0 | |||
} | |||
columnName := columns[i] | |||
opts := &models.SearchAvailableValueOptions{ | |||
Column: columnName, | |||
Framework: frameWork, | |||
FrameworkVersion: version, | |||
PythonVersion: pythonVersion, | |||
} | |||
ctx.JSON(http.StatusOK, models.BaseMessageWithDataApi{ | |||
Data: models.GetImageAvailableColumnValues(opts), | |||
}) | |||
} | |||
func getModelArtsImages(ctx *context.APIContext) { | |||
var versionInfos modelarts.VersionInfo | |||
@@ -9,6 +9,7 @@ import ( | |||
"time" | |||
"code.gitea.io/gitea/models" | |||
"code.gitea.io/gitea/modules/cloudbrain" | |||
"code.gitea.io/gitea/modules/context" | |||
"code.gitea.io/gitea/modules/convert" | |||
"code.gitea.io/gitea/modules/grampus" | |||
@@ -361,20 +362,11 @@ func QueryModelConvertResultFileList(ctx *context.APIContext, id string) ([]stor | |||
return nil, err | |||
} | |||
if job.IsGpuTrainTask() { | |||
//get dirs | |||
dirs, err := routerRepo.GetModelDirs(job.ID, parentDir) | |||
if err != nil { | |||
log.Error("GetModelDirs failed:%v", err.Error(), ctx.Data["msgID"]) | |||
return nil, err | |||
} | |||
var fileInfos []storage.FileInfo | |||
err = json.Unmarshal([]byte(dirs), &fileInfos) | |||
if err != nil { | |||
log.Error("json.Unmarshal failed:%v", err.Error(), ctx.Data["msgID"]) | |||
return nil, err | |||
} | |||
path := setting.CBCodePathPrefix + job.ID + cloudbrain.ModelMountPath + "/" | |||
log.Info("get model convert result file path=" + path) | |||
fileInfos, err := storage.GetAllObjectByBucketAndPrefixMinio(setting.Attachment.Minio.Bucket, path) | |||
if err == nil { | |||
for i, fileInfo := range fileInfos { | |||
temp, _ := time.Parse("2006-01-02 15:04:05", fileInfo.ModTime) | |||
fileInfos[i].ModTime = temp.Local().Format("2006-01-02 15:04:05") | |||
@@ -385,6 +377,10 @@ func QueryModelConvertResultFileList(ctx *context.APIContext, id string) ([]stor | |||
}) | |||
return fileInfos, nil | |||
} else { | |||
log.Info("query models path error.") | |||
return nil, err | |||
} | |||
} else { | |||
var versionName = "V0001" | |||
models, err := storage.GetObsListObject(job.ID, "output/", parentDir, versionName) | |||
@@ -21,6 +21,7 @@ import ( | |||
"code.gitea.io/gitea/modules/eventsource" | |||
"code.gitea.io/gitea/modules/modelappservice" | |||
userlogin "code.gitea.io/gitea/modules/context" | |||
"code.gitea.io/gitea/modules/git" | |||
"code.gitea.io/gitea/modules/highlight" | |||
code_indexer "code.gitea.io/gitea/modules/indexer/code" | |||
@@ -78,6 +79,8 @@ func NewServices() { | |||
log.Info("labelmsg.Init() succeed.") | |||
modelappservice.Init() | |||
log.Info("modelappservice.Init() succeed.") | |||
userlogin.UserActionChannelInit() | |||
log.Info("UserActionChannelInit succeed.") | |||
InitESClient() | |||
log.Info("ES Client succeed.") | |||
} | |||
@@ -1109,6 +1109,9 @@ func ModelConvertDownloadModel(ctx *context.Context) { | |||
jobName := ctx.Query("jobName") | |||
if job.IsGpuTrainTask() { | |||
filePath := "jobs/" + jobName + "/model/" + parentDir | |||
if !strings.HasSuffix(filePath, fileName) { | |||
filePath += fileName | |||
} | |||
url, err := storage.Attachments.PresignedGetURL(filePath, fileName) | |||
if err != nil { | |||
log.Error("PresignedGetURL failed: %v", err.Error(), ctx.Data["msgID"]) | |||
@@ -1227,6 +1227,13 @@ func CloudBrainImageEditPost(ctx *context.Context, form auth.EditImageCloudBrain | |||
} | |||
image.Description = form.Description | |||
image.Framework = form.Framework | |||
image.FrameworkVersion = form.FrameworkVersion | |||
image.CudaVersion = form.CudaVersion | |||
image.PythonVersion = form.PythonVersion | |||
image.OperationSystem = form.OperationSystem | |||
image.OperationSystemVersion = form.OperationSystemVersion | |||
image.ThirdPackages = form.ThirdPackages | |||
err = models.WithTx(func(ctx models.DBContext) error { | |||
if err := models.UpdateLocalImage(image); err != nil { | |||
@@ -1255,7 +1262,15 @@ func CloudBrainImageDelete(ctx *context.Context) { | |||
ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("repo.image_not_exist"))) | |||
return | |||
} | |||
image, err := models.GetImageByID(id) | |||
if err != nil { | |||
ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("repo.image_not_exist"))) | |||
return | |||
} | |||
err = grampus.DeleteImage(image) | |||
if err != nil { | |||
log.Info("Delete remote delete failed.error=" + err.Error()) | |||
} | |||
err = models.DeleteLocalImage(id) | |||
if err != nil { | |||
ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("repo.image_delete_fail"))) | |||
@@ -1304,6 +1319,14 @@ func CloudBrainAdminCommitImage(ctx *context.Context, form auth.CommitAdminImage | |||
UID: ctx.User.ID, | |||
Type: models.GetRecommondType(form.IsRecommend), | |||
Place: form.Place, | |||
Framework: form.Framework, | |||
FrameworkVersion: form.FrameworkVersion, | |||
CudaVersion: form.CudaVersion, | |||
PythonVersion: form.PythonVersion, | |||
OperationSystem: form.OperationSystem, | |||
OperationSystemVersion: form.OperationSystemVersion, | |||
ThirdPackages: form.ThirdPackages, | |||
ComputeResource: form.ComputeResource, | |||
}, ctx.User) | |||
if err != nil { | |||
log.Error("CommitImagefailed") | |||
@@ -1351,6 +1374,14 @@ func CloudBrainCommitImage(ctx *context.Context, form auth.CommitImageCloudBrain | |||
CloudBrainType: form.Type, | |||
Topics: validTopics, | |||
UID: ctx.User.ID, | |||
Framework: form.Framework, | |||
FrameworkVersion: form.FrameworkVersion, | |||
CudaVersion: form.CudaVersion, | |||
PythonVersion: form.PythonVersion, | |||
OperationSystem: form.OperationSystem, | |||
OperationSystemVersion: form.OperationSystemVersion, | |||
ThirdPackages: form.ThirdPackages, | |||
ComputeResource: form.ComputeResource, | |||
}, ctx.User) | |||
if err != nil { | |||
log.Error("CommitImage(%s) failed:%v", ctx.Cloudbrain.JobName, err.Error(), ctx.Data["msgID"]) | |||
@@ -1737,6 +1768,26 @@ func GetImages(ctx *context.Context, opts *models.SearchImageOptions) { | |||
} | |||
opts.SearchOrderBy = orderBy | |||
opts.Framework = ctx.Query("framework") | |||
opts.FrameworkVersion = ctx.Query("frameworkVersion") | |||
opts.CudaVersion = ctx.Query("cuda") | |||
opts.PythonVersion = ctx.Query("python") | |||
opts.OperationSystem = ctx.Query("os") | |||
opts.OperationSystemVersion = ctx.Query("osVersion") | |||
opts.ThirdPackages = ctx.Query("thirdParty") | |||
if ctx.QueryInt64("spec") > 0 { | |||
spec, err := models.FindSpecs(models.FindSpecsOptions{ | |||
SpecId: ctx.QueryInt64("spec"), | |||
}) | |||
if err == nil { | |||
opts.AiCenterId = spec[0].AiCenterCode | |||
} | |||
} | |||
computeResource := ctx.Query("computeResource") | |||
if computeResource != "" { | |||
opts.ComputeResource = computeResource | |||
} | |||
imageList, total, err := models.SearchImage(opts) | |||
if err != nil { | |||
@@ -1746,6 +1797,11 @@ func GetImages(ctx *context.Context, opts *models.SearchImageOptions) { | |||
Images: []*models.Image{}, | |||
}) | |||
} else { | |||
for _, tmp := range imageList { | |||
if tmp.Place == "" { | |||
tmp.Place = getImageUrl(tmp, opts.AiCenterId) | |||
} | |||
} | |||
ctx.JSON(http.StatusOK, models.ImagesPageResult{ | |||
Count: total, | |||
Images: imageList, | |||
@@ -1753,6 +1809,21 @@ func GetImages(ctx *context.Context, opts *models.SearchImageOptions) { | |||
} | |||
} | |||
func getImageUrl(image *models.Image, aiCenterID string) string { | |||
if image.AiCenterImages != nil { | |||
for _, tmp := range image.AiCenterImages { | |||
if aiCenterID == "" { | |||
return tmp.ImageUrl | |||
} | |||
if tmp.AiCenterId == aiCenterID { | |||
log.Info("tmp.url=" + tmp.ImageUrl) | |||
return tmp.ImageUrl | |||
} | |||
} | |||
} | |||
return "" | |||
} | |||
func getUID(ctx *context.Context) int64 { | |||
var uid int64 = -1 | |||
if ctx.IsSigned { | |||
@@ -1771,6 +1842,13 @@ func GetAllImages(ctx *context.Context) { | |||
IncludeOfficialOnly: ctx.QueryBool("recommend"), | |||
CloudbrainType: ctx.QueryInt("cloudbrainType"), | |||
Status: -1, | |||
Framework: ctx.Query("framework"), | |||
FrameworkVersion: ctx.Query("frameworkVesion"), | |||
CudaVersion: ctx.Query("cuda"), | |||
PythonVersion: ctx.Query("python"), | |||
OperationSystem: ctx.Query("os"), | |||
OperationSystemVersion: ctx.Query("osVersion"), | |||
ThirdPackages: ctx.Query("thirdParty"), | |||
} | |||
if ctx.Query("private") != "" { | |||
@@ -31,6 +31,7 @@ import ( | |||
"code.gitea.io/gitea/modules/git" | |||
"code.gitea.io/gitea/modules/grampus" | |||
"code.gitea.io/gitea/modules/modelarts" | |||
// "code.gitea.io/gitea/modules/notification" | |||
// "code.gitea.io/gitea/modules/timeutil" | |||
"code.gitea.io/gitea/modules/util" | |||
@@ -1961,13 +1962,20 @@ func GrampusNotebookRestart(ctx *context.Context) { | |||
} | |||
cloudbrainTask.GrampusNotebookRestart(ctx) | |||
} | |||
func getImageComputeResource(processType string) string { | |||
tail := strings.LastIndex(processType, "/") | |||
if tail > 0 { | |||
return strings.ToUpper(processType[tail+1:]) | |||
} | |||
return strings.ToUpper(processType) | |||
} | |||
func GrampusCommitImageShow(ctx *context.Context) { | |||
ctx.Data["PageIsCloudBrain"] = true | |||
ctx.Data["Type"] = ctx.Cloudbrain.Type | |||
if ctx.Cloudbrain.ComputeResource == models.NPUResource { | |||
ctx.Error(http.StatusBadRequest, "unsupported compute resource type") | |||
} | |||
ctx.Data["ComputeResource"] = getImageComputeResource(ctx.Cloudbrain.ComputeResource) | |||
ctx.HTML(200, tplGrampusNotebookGPUImageShow) | |||
} | |||
@@ -1989,7 +1997,7 @@ func GrampusCommitImage(ctx *context.Context, form auth.CommitImageGrampusForm) | |||
return | |||
} | |||
err := grampus.CommitImage(ctx.Cloudbrain.JobID, models.CommitGrampusImageParams{ | |||
err := grampus.CommitImage(ctx.Cloudbrain.JobID, ctx.Cloudbrain.ComputeResource, ctx.Cloudbrain.GetAiCenter(), models.CommitGrampusImageParams{ | |||
CommitImageGrampusParams: models.CommitImageGrampusParams{ | |||
ImageName: setting.Grampus.GPUImageCommonName, | |||
Description: form.Description, | |||
@@ -1999,6 +2007,14 @@ func GrampusCommitImage(ctx *context.Context, form auth.CommitImageGrampusForm) | |||
CloudBrainType: form.Type, | |||
Topics: validTopics, | |||
UID: ctx.User.ID, | |||
Framework: form.Framework, | |||
FrameworkVersion: form.FrameworkVersion, | |||
PythonVersion: form.PythonVersion, | |||
CudaVersion: form.CudaVersion, | |||
OperationSystem: form.OperationSystem, | |||
OperationSystemVersion: form.OperationSystemVersion, | |||
ThirdPackages: form.ThirdPackages, | |||
ComputeResource: form.ComputeResource, | |||
}, ctx.User) | |||
if err != nil { | |||
@@ -24,6 +24,11 @@ const ( | |||
USER_YEAR = 2023 | |||
) | |||
type ProjectsPeriodData struct { | |||
RecordBeginTime string `json:"recordBeginTime"` | |||
LastUpdatedTime string `json:"lastUpdatedTime"` | |||
} | |||
func getUserMetricsExcelHeader(ctx *context.Context) map[string]string { | |||
excelHeader := make([]string, 0) | |||
excelHeader = append(excelHeader, ctx.Tr("user.metrics.date")) | |||
@@ -749,6 +754,7 @@ func TimingCountDataByDate(date string) { | |||
func TimingCountData() { | |||
log.Info("start to time count data") | |||
context.UserActionMapClear() | |||
currentTimeNow := time.Now() | |||
log.Info("current time:" + currentTimeNow.Format("2006-01-02 15:04:05")) | |||
startTime := currentTimeNow.AddDate(0, 0, -1).Format("2006-01-02") | |||
@@ -951,3 +957,19 @@ func QueryUserAnnualReport(ctx *context.Context) { | |||
result := models.QueryUserAnnualReport(ctx.User.ID) | |||
ctx.JSON(http.StatusOK, result) | |||
} | |||
func getRecordBeginTime() (time.Time, error) { | |||
return time.ParseInLocation("2006-01-02", setting.RadarMap.RecordBeginTime, time.Local) | |||
} | |||
func QueryUserCountTimeInfo(ctx *context.Context) { | |||
recordBeginTime, err := getRecordBeginTime() | |||
if err != nil { | |||
recordBeginTime = time.Now() | |||
} | |||
projectsPeriodData := ProjectsPeriodData{ | |||
RecordBeginTime: recordBeginTime.Format("2006-01-02"), | |||
LastUpdatedTime: models.GetLastModifyTime(), | |||
} | |||
ctx.JSON(http.StatusOK, projectsPeriodData) | |||
} |
@@ -196,6 +196,12 @@ func NewMacaron() *macaron.Macaron { | |||
ExpiresAfter: setting.StaticCacheTime, | |||
}, | |||
)) | |||
m.Use(public.CustomJson( | |||
&public.Options{ | |||
SkipLogging: setting.DisableRouterLog, | |||
ExpiresAfter: 0, | |||
}, | |||
)) | |||
m.Use(public.StaticHandler( | |||
setting.AvatarUploadPath, | |||
&public.Options{ | |||
@@ -363,7 +369,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
m.Post("/all/search/", routers.Search) | |||
m.Get("/all/search/", routers.EmptySearch) | |||
m.Get("/all/dosearch/", routers.SearchApi) | |||
m.Post("/user/login/kanban", user.SignInPostAPI) | |||
m.Post("/user/login/kanban", user.SignInPostAPI, reqSignOut) | |||
m.Get("/home/term", routers.HomeTerm) | |||
m.Get("/home/annual_privacy", routers.HomeAnnual) | |||
m.Get("/home/model_privacy", routers.HomeWenxin) | |||
@@ -538,7 +544,6 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
m.Post("/unbind", authentication.UnbindWechat) | |||
m.Get("/bind", authentication.GetBindPage) | |||
}, reqSignIn) | |||
m.Group("/user/settings", func() { | |||
m.Get("", userSetting.Profile) | |||
m.Post("", bindIgnErr(auth.UpdateProfileForm{}), userSetting.ProfilePost) | |||
@@ -581,6 +586,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
m.Post("/delete", userSetting.DeleteOAuth2Application) | |||
m.Post("/revoke", userSetting.RevokeOAuth2Grant) | |||
}) | |||
m.Combo("/applications").Get(userSetting.Applications). | |||
Post(bindIgnErr(auth.NewAccessTokenForm{}), userSetting.ApplicationsPost) | |||
m.Post("/applications/delete", userSetting.DeleteApplication) | |||
@@ -306,7 +306,7 @@ func SignInPostAPI(ctx *context.Context) { | |||
ctx.Data["Title"] = ctx.Tr("sign_in") | |||
UserName := ctx.Query("UserName") | |||
Password := ctx.Query("Password") | |||
log.Info("0000000") | |||
log.Info("u=" + UserName) | |||
orderedOAuth2Names, oauth2Providers, err := models.GetActiveOAuth2Providers() | |||
if err != nil { | |||
ctx.ServerError("UserSignIn", err) | |||
@@ -327,6 +327,7 @@ func SignInPostAPI(ctx *context.Context) { | |||
} | |||
u, err := models.UserSignIn(UserName, Password) | |||
if err != nil { | |||
log.Info("login failed.UserName=" + UserName + " Password=" + Password) | |||
ctx.ServerError("UserSignIn", err) | |||
return | |||
} | |||
@@ -786,7 +787,6 @@ func handleSignInFullNotRedirect(ctx *context.Context, u *models.User, remember | |||
} | |||
ctx.SetCookie("lang", u.Language, nil, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true) | |||
// Clear whatever CSRF has right now, force to generate a new one | |||
ctx.SetCookie(setting.CSRFCookieName, "", -1, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true) | |||
@@ -91,14 +91,14 @@ func (c C2NetClusterAdapter) GetNotebookImages(req entity.GetImageReq, centerId | |||
return r, false, nil | |||
} | |||
func hasIntersection(imageCenterInfos []models.AICenterImage, centerId ...string) bool { | |||
func hasIntersection(imageCenterInfos []models.AiCenterImage, centerId ...string) bool { | |||
if len(centerId) == 0 || len(imageCenterInfos) == 0 { | |||
//如果没传centerId或者查询的镜像不含可用中心信息,不进行判断,直接返回true | |||
return true | |||
} | |||
for _, aicenterImage := range imageCenterInfos { | |||
for _, centerCode := range centerId { | |||
if aicenterImage.AICenterID == centerCode { | |||
if aicenterImage.AiCenterId == centerCode { | |||
return true | |||
} | |||
} | |||
@@ -294,6 +294,7 @@ func getGrampusAvailableCenterIds(queues []models.ResourceQueue, imageId string, | |||
} | |||
processType := computeSource.FullName | |||
log.Info("processType=" + computeSource.FullName + " jobType=" + string(jobType)) | |||
images, err := grampus.GetImages(processType, string(jobType)) | |||
if err != nil { | |||
log.Warn("can not get image info from grampus", err) | |||
@@ -303,11 +304,24 @@ func getGrampusAvailableCenterIds(queues []models.ResourceQueue, imageId string, | |||
for _, image := range images.Infos { | |||
if image.ID == imageId { | |||
for _, centerInfo := range image.AICenterImage { | |||
imageCenterIds = append(imageCenterIds, centerInfo.AICenterID) | |||
imageCenterIds = append(imageCenterIds, centerInfo.AiCenterId) | |||
} | |||
break | |||
} | |||
} | |||
images, err = grampus.GetUserImages(processType, string(jobType)) | |||
if err == nil { | |||
for _, image := range images.Infos { | |||
if image.ID == imageId { | |||
for _, centerInfo := range image.AICenterImage { | |||
imageCenterIds = append(imageCenterIds, centerInfo.AiCenterId) | |||
} | |||
break | |||
} | |||
} | |||
} else { | |||
log.Warn("can not get user image info from grampus", err) | |||
} | |||
if len(imageCenterIds) == 0 { | |||
return []string{}, errors.New("image not available") | |||
} | |||
@@ -29,7 +29,12 @@ func (b *DatasetBuilder) Build(ctx *context.CreationContext) ([]entity.Container | |||
var data []entity.ContainerData | |||
//如果是智算GPU调试任务,需要把dataset文件夹也挂载,这样提交镜像时才不会把dataset下的文件提交到镜像中 | |||
if ctx.Request.Cluster == entity.C2Net && (ctx.Request.JobType == models.JobTypeDebug || ctx.Request.JobType == models.JobTypeTrain) && ctx.Request.ComputeSource.Name == models.GPU { | |||
if ctx.Request.Cluster == entity.C2Net && (ctx.Request.JobType == models.JobTypeDebug || ctx.Request.JobType == models.JobTypeTrain) && | |||
(ctx.Request.ComputeSource.Name == models.GPU || | |||
ctx.Request.ComputeSource.Name == models.MLU || | |||
ctx.Request.ComputeSource.Name == models.GCU || | |||
ctx.Request.ComputeSource.Name == models.ILUVATAR || | |||
ctx.Request.ComputeSource.Name == models.METAX) { | |||
log.Info("mount dataset directory.") | |||
jobName := ctx.Request.JobName | |||
storageTypes := b.Opts.AcceptStorageType | |||
@@ -115,9 +115,25 @@ func GetAvailableImageInfoBySpec(req entity.GetAITaskCreationImageInfoReq) (*ent | |||
UserId: req.UserID, | |||
JobType: req.JobType, | |||
}) | |||
//load from db | |||
reImages := make([]entity.ClusterImage, 0, 10) | |||
result.Images = reImages | |||
log.Info("start to query db,params=" + req.ComputeSource.FullName + " 2=" + req.ComputeSource.Name) | |||
imageList, dbErr := models.GetImageByComputeResource(req.ComputeSource.Name) | |||
if dbErr != nil { | |||
log.Info("query error" + dbErr.Error()) | |||
} else { | |||
for _, tmpImage := range imageList { | |||
clusterImage := entity.ClusterImage{ | |||
ImageId: tmpImage.ImageID, | |||
ImageName: tmpImage.Tag, | |||
ImageUrl: tmpImage.Place, | |||
} | |||
result.Images = append(result.Images, clusterImage) | |||
} | |||
} | |||
if images, canUseAll, err := t.GetImages(*req.ComputeSource, centerIds...); err == nil { | |||
result.Images = images | |||
result.Images = append(result.Images, images...) | |||
result.CanUseAllImages = canUseAll | |||
} | |||
return result, nil | |||
@@ -1,10 +1,12 @@ | |||
package resource | |||
import ( | |||
"fmt" | |||
"strings" | |||
"code.gitea.io/gitea/models" | |||
"code.gitea.io/gitea/modules/grampus" | |||
"code.gitea.io/gitea/modules/log" | |||
"fmt" | |||
) | |||
func AddResourceQueue(req models.ResourceQueueReq) error { | |||
@@ -54,6 +56,69 @@ func GetResourceAiCenters() ([]models.ResourceAiCenterRes, error) { | |||
return r, nil | |||
} | |||
func filterGrampusImage(all []models.GrampusImage) []models.GrampusImage { | |||
result := make([]models.GrampusImage, 0) | |||
for _, tmp := range all { | |||
computeResource := getComputeResourceByProcessType(tmp.ProcessorType) | |||
if computeResource == "GCU" || computeResource == "MLU" || computeResource == "ILUVATAR-GPGPU" || computeResource == "METAX-GPGPU" { | |||
result = append(result, tmp) | |||
} | |||
} | |||
return result | |||
} | |||
func getComputeResourceByProcessType(processType string) string { | |||
tail := strings.LastIndex(processType, "/") | |||
if tail > 0 { | |||
return strings.ToUpper(processType[tail+1:]) | |||
} | |||
return strings.ToUpper(processType) | |||
} | |||
func SyncGrampusImage(doerId int64) error { | |||
allImage, err := grampus.GetAllBaseImages() | |||
if err == nil { | |||
log.Info("Query image from grampus, length=" + fmt.Sprint(len(allImage.Infos))) | |||
dbAllImage, err := models.GetGrampusAllBaseImage() | |||
if err == nil { | |||
log.Info("start to deal db image update.") | |||
filterGrampusImageList := filterGrampusImage(allImage.Infos) | |||
log.Info("sync grampus image length=." + fmt.Sprint(len(filterGrampusImageList))) | |||
grampusMap := make(map[string]models.GrampusImage, 0) | |||
for _, image := range filterGrampusImageList { | |||
grampusMap[image.ID] = image | |||
} | |||
dbMap := make(map[string]*models.Image, 0) | |||
for _, image := range dbAllImage { | |||
dbMap[image.HuJingId] = image | |||
} | |||
insertList := make([]models.GrampusImage, 0) | |||
updateList := make([]models.GrampusImage, 0) | |||
updateDbList := make([]*models.Image, 0) | |||
for _, image := range filterGrampusImageList { | |||
if dbImage, ok := dbMap[image.ID]; !ok { | |||
insertList = append(insertList, image) | |||
} else { | |||
updateList = append(updateList, image) | |||
updateDbList = append(updateDbList, dbImage) | |||
} | |||
} | |||
deleteList := make([]*models.Image, 0) | |||
for _, image := range dbAllImage { | |||
if _, ok := grampusMap[image.HuJingId]; !ok { | |||
deleteList = append(deleteList, image) | |||
} | |||
} | |||
models.SyncGrampusAllBaseImageToDb(insertList, updateList, updateDbList, deleteList, doerId) | |||
} else { | |||
log.Error("failed query image db.error=" + err.Error()) | |||
} | |||
} else { | |||
log.Error("failed query image grampus.error=" + err.Error()) | |||
} | |||
return err | |||
} | |||
func SyncGrampusQueue(doerId int64) error { | |||
r, err := grampus.GetResourceQueue() | |||
if err != nil { | |||
@@ -1,152 +1,14 @@ | |||
<style> | |||
.label_color{ | |||
color:#505559 !important; | |||
width: 6% !important; | |||
text-align: center; | |||
} | |||
</style> | |||
{{template "base/head" .}} | |||
<div id="mask"> | |||
<div id="loadingPage"> | |||
<div class="rect1"></div> | |||
<div class="rect2"></div> | |||
<div class="rect3"></div> | |||
<div class="rect4"></div> | |||
<div class="rect5"></div> | |||
</div> | |||
</div> | |||
<div class="repository"> | |||
{{template "repo/header" .}} | |||
<div class="alert"></div> | |||
<div class="ui container"> | |||
<div> | |||
<div class="ui negative message" style="display: none;"> | |||
</div> | |||
<div class="ui info message" style="display: none;"> | |||
</div> | |||
<div class="ui positive message" style="display: none;"> | |||
</div> | |||
<h4 class="ui top attached header"> | |||
{{.i18n.Tr "repo.submit_image"}} | |||
</h4> | |||
<div class="submit-image-tmplvalue" style="display: none;" data-link="{{$.Link}}" data-edit-page="{{.PageIsAdminImages}}"></div> | |||
<div class="ui attached segment" style="padding: 2em 3em;padding-bottom: 7rem;"> | |||
<div class="ui form" id="form_image"> | |||
<input type="hidden" name="edit" value="edit"> | |||
{{.CsrfTokenHtml}} | |||
<div class="inline field"> | |||
<label class="label_color" for="">{{$.i18n.Tr "dataset.dataset_available_clusters"}}</label> | |||
<!-- <div class="ui basic label" style="border: none !important;color:#3291f8;"> | |||
<svg class="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="14" height="14"><path fill="none" d="M0 0h24v24H0z"></path><path d="M4 3h16a1 1 0 0 1 1 1v7H3V4a1 1 0 0 1 1-1zM3 13h18v7a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1v-7zm4 3v2h3v-2H7zM7 6v2h3V6H7z"></path></svg> | |||
CPU/GPU | |||
</div> --> | |||
<div class="ui blue mini menu compact selectcloudbrain" id="adminCommitImage"> | |||
<a class="active item" data-type="0"> | |||
<svg class="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16"> | |||
<path fill="none" d="M0 0h24v24H0z"/> | |||
<path d="M3 2.992C3 2.444 3.445 2 3.993 2h16.014a1 1 0 0 1 .993.992v18.016a.993.993 0 0 1-.993.992H3.993A1 1 0 0 1 3 21.008V2.992zM19 11V4H5v7h14zm0 2H5v7h14v-7zM9 6h6v2H9V6zm0 9h6v2H9v-2z"/> | |||
</svg> | |||
启智CPU/GPU | |||
</a> | |||
<a class="item" data-type="2"> | |||
<svg class="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16"> | |||
<path fill="none" d="M0 0h24v24H0z"/> | |||
<path d="M3 2.992C3 2.444 3.445 2 3.993 2h16.014a1 1 0 0 1 .993.992v18.016a.993.993 0 0 1-.993.992H3.993A1 1 0 0 1 3 21.008V2.992zM19 11V4H5v7h14zm0 2H5v7h14v-7zM9 6h6v2H9V6zm0 9h6v2H9v-2z"/> | |||
</svg> | |||
智算CPU/GPU | |||
</a> | |||
</div> | |||
<input type="hidden" value="0" name="type"> | |||
</div> | |||
<div class="inline required field"> | |||
<label class="label_color" for="">{{$.i18n.Tr "repo.images.name"}}</label> | |||
<input type="text" name="tag" required placeholder="{{$.i18n.Tr "repo.images.name_placerholder"}}" style="width: 80%;" maxlength="100"> | |||
<span class="tooltips" style="display: block;padding-left: 1.5rem;"> | |||
{{.i18n.Tr "repo.images.name_rule50"}} | |||
</span> | |||
</div> | |||
<div class="inline required field"> | |||
<label class="label_color" for="">{{$.i18n.Tr "repo.images"}}</label> | |||
<input type="text" name="place" required placeholder="{{$.i18n.Tr "cloudbrain.input_mirror"}}" style="width: 80%;" maxlength="300"> | |||
</div> | |||
<div class="inline required field"> | |||
<label class="label_color" for="">{{$.i18n.Tr "dataset.description"}}</label> | |||
<textarea style="width: 80%;" required id="description" name="description" rows="3" maxlength="1000" placeholder={{.i18n.Tr "repo.images.descr_placerholder"}} onchange="this.value=this.value.substring(0, 1000)" onkeydown="this.value=this.value.substring(0, 1000)" onkeyup="this.value=this.value.substring(0, 1000)"></textarea> | |||
</div> | |||
<div class="inline field" style="display: flex;align-items: center;"> | |||
<label class="label_color" for="">{{$.i18n.Tr "repo.model.manage.label"}}</label> | |||
<div class="ui multiple search selection dropdown" id="dropdown_image" style="width: 80%;"> | |||
<input type="hidden" name="topics" value="" required> | |||
<div class="default text" id="default_text">{{.i18n.Tr "repo.repo_label_helpe"}}</div> | |||
<div class="menu" id="course_label_item"></div> | |||
</div> | |||
</div> | |||
<span class="tooltips" style="display: block;padding-left: 1.5rem;margin-top: 0.5rem;margin-bottom: 1rem;">{{.i18n.Tr "repo.image.label_tooltips"}}</span> | |||
<div class="inline fields"> | |||
<label class="label_color" for="" style="visibility: hidden;"></label> | |||
<div class="field"> | |||
<div class="ui radio checkbox"> | |||
<input type="radio" name="isRecommend" checked="checked" value="true"> | |||
<label>{{.i18n.Tr "admin.images.recommend"}}</label> | |||
</div> | |||
</div> | |||
<div class="field" style="flex: 0.15;"> | |||
<div class="ui radio checkbox" > | |||
<input type="radio" name="isRecommend" value="false"> | |||
<label>{{.i18n.Tr "admin.images.unrecommend"}}</label> | |||
</div> | |||
</div> | |||
</div> | |||
<!-- | |||
<div class="inline fields"> | |||
<label class="label_color" for="" style="visibility: hidden;"></label> | |||
<div class="field"> | |||
<div class="ui radio checkbox"> | |||
<input type="radio" name="isPrivate" checked="checked" value="false"> | |||
<label>{{.i18n.Tr "org.settings.visibility.public"}}</label> | |||
</div> | |||
</div> | |||
<div class="field" style="flex: 0.15;"> | |||
<div class="ui radio checkbox" > | |||
<input type="radio" name="isPrivate" value="true"> | |||
<label>{{.i18n.Tr "home.show_private"}}</label> | |||
</div> | |||
</div> | |||
<div class="field"> | |||
<span class="label_color">{{.i18n.Tr "repo.images.public_tooltips"}}</span> | |||
</div> | |||
</div> | |||
--> | |||
<div class="inline required field"> | |||
<label class="label_color" for="" style="visibility: hidden;"></label> | |||
<span style="color: rgb(255, 94, 0);display: inline-flex;"><i class="ri-error-warning-line" style="margin-right: 0.3rem;"></i>{{.i18n.Tr "repo.images.submit_tooltips"}}</span> | |||
</div> | |||
<div class="inline required field"> | |||
<label class="label_color" for="" style="visibility: hidden;"></label> | |||
<button class="ui create_image green button" type="button"> | |||
{{.i18n.Tr "repo.cloudbrain.commit_image"}} | |||
</button> | |||
<a class="ui button" id="cancel_submit_image">{{.i18n.Tr "repo.cloudbrain.cancel"}}</a> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
<!-- 确认模态框 --> | |||
<div> | |||
<div class="ui modal image_confirm_submit"> | |||
<div class="header">{{.i18n.Tr "repo.submit_image"}}</div> | |||
<div class="content text red center"> | |||
<p><i class="exclamation icon"></i>{{.i18n.Tr "repo.image_overwrite"}}</p> | |||
</div> | |||
<div class="actions"> | |||
<button class="ui deny small button">{{.i18n.Tr "cloudbrain.operate_cancel"}}</button> | |||
<button class="ui green small approve button">{{.i18n.Tr "cloudbrain.operate_confirm"}}</button> | |||
</div> | |||
</div> | |||
<script> | |||
window._PageType = "submitAdmin"; | |||
window._Image = {{.Image}}; | |||
window._PageFrom = 'imageAdmin'; | |||
window._PageSubmitLink = "{{$.Link}}"; | |||
</script> | |||
<link rel="stylesheet" href="{{StaticUrlPrefix}}/css/vp-images-submit.css?v={{MD5 AppVer}}" /> | |||
<div id="__vue-root"></div> | |||
<script src="{{StaticUrlPrefix}}/js/vp-images-submit.js?v={{MD5 AppVer}}"></script> | |||
</div> | |||
{{template "base/footer" .}} |
@@ -1,26 +1,5 @@ | |||
{{template "base/head" .}} | |||
<div class="alert"></div> | |||
<div id="images"></div> | |||
<!-- 确认模态框 --> | |||
<div id="deletemodel"> | |||
<div class="ui basic modal images"> | |||
<div class="ui icon header"> | |||
<i class="trash icon"></i> {{.i18n.Tr "repo.images.delete_task"}} | |||
</div> | |||
<div class="content"> | |||
<p>{{.i18n.Tr "repo.images.task_delete_confirm"}}</p> | |||
</div> | |||
<div class="actions"> | |||
<div class="ui red basic inverted cancel button"> | |||
<i class="remove icon"></i> | |||
{{.i18n.Tr "cloudbrain.operate_cancel"}} | |||
</div> | |||
<div class="ui green basic inverted ok button"> | |||
<i class="checkmark icon"></i> | |||
{{.i18n.Tr "cloudbrain.operate_confirm"}} | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
<link rel="stylesheet" href="{{StaticUrlPrefix}}/css/vp-images-square.css?v={{MD5 AppVer}}" /> | |||
<div id="__vue-root"></div> | |||
<script src="{{StaticUrlPrefix}}/js/vp-images-square.js?v={{MD5 AppVer}}"></script> | |||
{{template "base/footer" .}} |
@@ -1,126 +1,14 @@ | |||
<style> | |||
.label_color{ | |||
color:#505559 !important; | |||
width: 6% !important; | |||
text-align: center; | |||
} | |||
.descr-tip-box { | |||
display: inline-block; | |||
border: 1px solid #f2711c; | |||
background-color: rgba(242,113,28,0.05); | |||
width: 80%; | |||
padding: 10px; | |||
} | |||
.descr-tip-head { | |||
color: #888888; | |||
font-size: 14px; | |||
margin-bottom: 4px; | |||
} | |||
.descr-tip-item { | |||
margin: 2px 0; | |||
padding-left: 10px; | |||
color: rgb(242 113 28); | |||
font-size: 12px; | |||
} | |||
</style> | |||
{{template "base/head" .}} | |||
<div id="mask"> | |||
<div id="loadingPage"> | |||
<div class="rect1"></div> | |||
<div class="rect2"></div> | |||
<div class="rect3"></div> | |||
<div class="rect4"></div> | |||
<div class="rect5"></div> | |||
</div> | |||
</div> | |||
<div class="repository"> | |||
{{template "repo/header" .}} | |||
<div class="alert"></div> | |||
<div class="ui container"> | |||
<div> | |||
<div class="ui negative message" style="display: none;"> | |||
</div> | |||
<div class="ui info message" style="display: none;"> | |||
</div> | |||
<div class="ui positive message" style="display: none;"> | |||
</div> | |||
<h4 class="ui top attached header"> | |||
{{$.i18n.Tr "admin.images.applyrecommendImage"}} | |||
</h4> | |||
<div class="submit-image-tmplvalue" style="display: none;" data-link="/image/{{$.Image.ID}}/apply" data-edit-page="{{.PageFrom}}"></div> | |||
<div class="ui attached segment" style="padding: 2em 3em;padding-bottom: 7rem;"> | |||
<div class="ui form" id="form_image"> | |||
<input type="hidden" name="edit" value="edit"> | |||
{{.CsrfTokenHtml}} | |||
<input type="hidden" name="id" value="{{.Image.ID}}"> | |||
<div class="inline field"> | |||
<label class="label_color" for="">{{$.i18n.Tr "dataset.dataset_available_clusters"}}</label> | |||
<div class="ui basic label" style="border: none !important;color:#3291f8;"> | |||
<svg class="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="14" height="14"><path fill="none" d="M0 0h24v24H0z"></path><path d="M4 3h16a1 1 0 0 1 1 1v7H3V4a1 1 0 0 1 1-1zM3 13h18v7a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1v-7zm4 3v2h3v-2H7zM7 6v2h3V6H7z"></path></svg> | |||
{{if eq .Image.CloudbrainType 2}} | |||
{{$.i18n.Tr "cloudbrain.resource_cluster_c2net_simple"}} GPU | |||
{{else}} | |||
{{$.i18n.Tr "cloudbrain.resource_cluster_openi_simple"}} GPU | |||
{{end}} | |||
</div> | |||
<input type="hidden" value="{{.Image.CloudbrainType}}" name="type"> | |||
</div> | |||
<div class="inline required field"> | |||
<label class="label_color" for="">{{$.i18n.Tr "repo.images.name"}}</label> | |||
<input type="hidden" name="tag" value="{{.Image.Tag}}" > | |||
<input disabled value="{{.Image.Tag}}" style="width: 80%;"> | |||
<span class="tooltips" style="display: block;padding-left: 1.5rem;"> | |||
{{if eq .Image.CloudbrainType 2}} | |||
{{.i18n.Tr "repo.images.name_rule50"}} | |||
{{else}} | |||
{{.i18n.Tr "repo.images.name_rule100"}} | |||
{{end}} | |||
</span> | |||
</div> | |||
<div class="inline required field"> | |||
<label class="label_color" for="">{{$.i18n.Tr "dataset.description"}}</label> | |||
<textarea style="width: 80%;" required id="description" value="{{.Image.Description}}" name="description" rows="3" maxlength="1000" placeholder={{.i18n.Tr "repo.images.descr_placerholder"}} onchange="this.value=this.value.substring(0, 1000)" onkeydown="this.value=this.value.substring(0, 1000)" onkeyup="this.value=this.value.substring(0, 1000)">{{.Image.Description}}</textarea> | |||
</div> | |||
<div class="inline field"> | |||
<label class="label_color" style="color:transparent !important;">x</label> | |||
<div class="descr-tip-box"> | |||
<div class="descr-tip-head">{{$.i18n.Tr "admin.images.descrTip"}}</div> | |||
<div class="descr-tip-item">{{$.i18n.Tr "admin.images.framework"}}:pytorch1.9.1;</div> | |||
<div class="descr-tip-item">CUDA:cuda11;</div> | |||
<div class="descr-tip-item">{{$.i18n.Tr "admin.images.pythonVersion"}}:python 3.7.11;</div> | |||
<div class="descr-tip-item">{{$.i18n.Tr "admin.images.operatingSystem"}}:Ubuntu 20.02;</div> | |||
<div class="descr-tip-item">{{$.i18n.Tr "admin.images.installedSoftwarePackage"}}:numpy1.21.2</div> | |||
</div> | |||
</div> | |||
<div class="inline field" style="display: flex;align-items: center;"> | |||
{{$lenTopics := len .Image.Topics}} | |||
{{$subTopics := subOne $lenTopics}} | |||
<label class="label_color" for="">{{$.i18n.Tr "repo.model.manage.label"}}</label> | |||
<div class="ui multiple search selection dropdown" id="dropdown_image" style="width: 80%;"> | |||
<input type="hidden" name="topics" value="{{range $k,$v := .Image.Topics}}{{$v}}{{if ne $k $subTopics}},{{end}}{{end}}" required> | |||
{{range .Image.Topics}} | |||
<a class="ui label transition visible" data-value="{{.}}" style="display: inline-block !important;">{{.}}<i class="delete icon"></i></a> | |||
{{end}} | |||
<div class="default text" id="default_text">{{.i18n.Tr "repo.repo_label_helpe"}}</div> | |||
<div class="menu" id="course_label_item"></div> | |||
</div> | |||
</div> | |||
<span class="tooltips" style="display: block;padding-left: 1.5rem;margin-top: 0.5rem;margin-bottom: 1rem;">{{.i18n.Tr "repo.image.label_tooltips"}}</span> | |||
<div class="inline required field" style="padding-top: 2rem;"> | |||
<label class="label_color" for="" style="visibility: hidden;"></label> | |||
<button class="ui create_image green button" type="button"> | |||
{{$.i18n.Tr "admin.images.submitApply"}} | |||
</button> | |||
<a class="ui button" id="cancel_submit_image">{{.i18n.Tr "repo.cloudbrain.cancel"}}</a> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
{{template "base/footer" .}} | |||
<script> | |||
;(function(){ | |||
var Images = {{.Image}}; | |||
})(); | |||
window._PageType = "apply"; | |||
window._Image = {{.Image}}; | |||
window._PageFrom = {{.PageFrom}}; | |||
window._PageSubmitLink = "/image/{{$.Image.ID}}/apply"; | |||
</script> | |||
<link rel="stylesheet" href="{{StaticUrlPrefix}}/css/vp-images-submit.css?v={{MD5 AppVer}}" /> | |||
<div id="__vue-root"></div> | |||
<script src="{{StaticUrlPrefix}}/js/vp-images-submit.js?v={{MD5 AppVer}}"></script> | |||
</div> | |||
{{template "base/footer" .}} |
@@ -1,119 +1,14 @@ | |||
<style> | |||
.label_color{ | |||
color:#505559 !important; | |||
width: 6% !important; | |||
text-align: center; | |||
} | |||
</style> | |||
{{template "base/head" .}} | |||
<div id="mask"> | |||
<div id="loadingPage"> | |||
<div class="rect1"></div> | |||
<div class="rect2"></div> | |||
<div class="rect3"></div> | |||
<div class="rect4"></div> | |||
<div class="rect5"></div> | |||
</div> | |||
</div> | |||
<div class="repository"> | |||
{{template "repo/header" .}} | |||
<div class="alert"></div> | |||
<div class="ui container"> | |||
<div> | |||
<div class="ui negative message" style="display: none;"> | |||
</div> | |||
<div class="ui info message" style="display: none;"> | |||
</div> | |||
<div class="ui positive message" style="display: none;"> | |||
</div> | |||
<h4 class="ui top attached header"> | |||
{{.i18n.Tr "repo.modify_image"}} | |||
</h4> | |||
<div class="submit-image-tmplvalue" style="display: none;" data-link="/image/{{$.Image.ID}}" data-edit-page="{{.PageFrom}}"></div> | |||
<div class="ui attached segment" style="padding: 2em 3em;padding-bottom: 7rem;"> | |||
<div class="ui form" id="form_image"> | |||
<input type="hidden" name="edit" value="edit"> | |||
{{.CsrfTokenHtml}} | |||
<input type="hidden" name="id" value="{{.Image.ID}}"> | |||
<div class="inline field"> | |||
<label class="label_color" for="">{{$.i18n.Tr "dataset.dataset_available_clusters"}}</label> | |||
<div class="ui basic label" style="border: none !important;color:#3291f8;"> | |||
<svg class="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="14" height="14"><path fill="none" d="M0 0h24v24H0z"></path><path d="M4 3h16a1 1 0 0 1 1 1v7H3V4a1 1 0 0 1 1-1zM3 13h18v7a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1v-7zm4 3v2h3v-2H7zM7 6v2h3V6H7z"></path></svg> | |||
{{if eq .Image.CloudbrainType 2}} | |||
{{$.i18n.Tr "cloudbrain.resource_cluster_c2net_simple"}} GPU | |||
{{else}} | |||
{{$.i18n.Tr "cloudbrain.resource_cluster_openi_simple"}} GPU | |||
{{end}} | |||
</div> | |||
<input type="hidden" value="{{.Image.CloudbrainType}}" name="type"> | |||
</div> | |||
<div class="inline required field"> | |||
<label class="label_color" for="">{{$.i18n.Tr "repo.images.name"}}</label> | |||
<input type="hidden" name="tag" value="{{.Image.Tag}}" > | |||
<input disabled value="{{.Image.Tag}}" style="width: 80%;"> | |||
<span class="tooltips" style="display: block;padding-left: 1.5rem;"> | |||
{{if eq .Image.CloudbrainType 2}} | |||
{{.i18n.Tr "repo.images.name_rule50"}} | |||
{{else}} | |||
{{.i18n.Tr "repo.images.name_rule100"}} | |||
{{end}} | |||
</span> | |||
</div> | |||
<div class="inline required field"> | |||
<label class="label_color" for="">{{$.i18n.Tr "dataset.description"}}</label> | |||
<textarea style="width: 80%;" required id="description" value="{{.Image.Description}}" name="description" rows="3" maxlength="1000" placeholder={{.i18n.Tr "repo.images.descr_placerholder"}} onchange="this.value=this.value.substring(0, 1000)" onkeydown="this.value=this.value.substring(0, 1000)" onkeyup="this.value=this.value.substring(0, 1000)">{{.Image.Description}}</textarea> | |||
</div> | |||
<div class="inline field" style="display: flex;align-items: center;"> | |||
{{$lenTopics := len .Image.Topics}} | |||
{{$subTopics := subOne $lenTopics}} | |||
<label class="label_color" for="">{{$.i18n.Tr "repo.model.manage.label"}}</label> | |||
<div class="ui multiple search selection dropdown" id="dropdown_image" style="width: 80%;"> | |||
<input type="hidden" name="topics" value="{{range $k,$v := .Image.Topics}}{{$v}}{{if ne $k $subTopics}},{{end}}{{end}}" required> | |||
{{range .Image.Topics}} | |||
<a class="ui label transition visible" data-value="{{.}}" style="display: inline-block !important;">{{.}}<i class="delete icon"></i></a> | |||
{{end}} | |||
<div class="default text" id="default_text">{{.i18n.Tr "repo.repo_label_helpe"}}</div> | |||
<div class="menu" id="course_label_item"></div> | |||
</div> | |||
</div> | |||
<span class="tooltips" style="display: block;padding-left: 1.5rem;margin-top: 0.5rem;margin-bottom: 1rem;">{{.i18n.Tr "repo.image.label_tooltips"}}</span> | |||
<!-- | |||
<div class="inline fields"> | |||
<label class="label_color" for="" style="visibility: hidden;"></label> | |||
<div class="field"> | |||
<div class="ui radio checkbox"> | |||
<input type="radio" name="isPrivate" {{if not .Image.IsPrivate}} checked {{end}} value="false"> | |||
<label>{{.i18n.Tr "org.settings.visibility.public"}}</label> | |||
</div> | |||
</div> | |||
<div class="field" style="flex: 0.15;"> | |||
<div class="ui radio checkbox" > | |||
<input type="radio" name="isPrivate" {{if .Image.IsPrivate}} checked {{end}} value="true"> | |||
<label>{{.i18n.Tr "home.show_private"}}</label> | |||
</div> | |||
</div> | |||
<div class="field"> | |||
<span class="label_color">{{.i18n.Tr "repo.images.public_tooltips"}}</span> | |||
</div> | |||
</div> | |||
--> | |||
<div class="inline required field"> | |||
<label class="label_color" for="" style="visibility: hidden;"></label> | |||
<span style="color: rgb(255, 94, 0);display: inline-flex;"><i class="ri-error-warning-line" style="margin-right: 0.3rem;"></i>{{.i18n.Tr "repo.images.submit_tooltips"}}</span> | |||
</div> | |||
<div class="inline required field"> | |||
<label class="label_color" for="" style="visibility: hidden;"></label> | |||
<button class="ui create_image green button" type="button"> | |||
{{.i18n.Tr "explore.save"}} | |||
</button> | |||
<a class="ui button" id="cancel_submit_image">{{.i18n.Tr "repo.cloudbrain.cancel"}}</a> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
{{template "base/footer" .}} | |||
<script> | |||
console.log({{.Image}}) | |||
window._PageType = "edit"; | |||
window._Image = {{.Image}}; | |||
window._PageFrom = {{.PageFrom}}; | |||
window._PageSubmitLink = "/image/{{$.Image.ID}}"; | |||
</script> | |||
<link rel="stylesheet" href="{{StaticUrlPrefix}}/css/vp-images-submit.css?v={{MD5 AppVer}}" /> | |||
<div id="__vue-root"></div> | |||
<script src="{{StaticUrlPrefix}}/js/vp-images-submit.js?v={{MD5 AppVer}}"></script> | |||
</div> | |||
{{template "base/footer" .}} |
@@ -1,123 +1,17 @@ | |||
<style> | |||
.label_color{ | |||
color:#505559 !important; | |||
width: 6% !important; | |||
text-align: center; | |||
} | |||
</style> | |||
{{template "base/head" .}} | |||
<div id="mask"> | |||
<div id="loadingPage"> | |||
<div class="rect1"></div> | |||
<div class="rect2"></div> | |||
<div class="rect3"></div> | |||
<div class="rect4"></div> | |||
<div class="rect5"></div> | |||
</div> | |||
</div> | |||
<div class="repository"> | |||
{{template "repo/header" .}} | |||
<div class="alert"></div> | |||
<div class="ui container"> | |||
<div> | |||
<div class="ui negative message" style="display: none;"> | |||
</div> | |||
<div class="ui info message" style="display: none;"> | |||
</div> | |||
<div class="ui positive message" style="display: none;"> | |||
</div> | |||
<h4 class="ui top attached header"> | |||
{{.i18n.Tr "repo.submit_image"}} | |||
</h4> | |||
<div class="submit-image-tmplvalue" style="display: none;" data-link="{{$.Link}}" data-repo-link="{{$.RepoLink}}" data-edit-page="submit"></div> | |||
<div class="ui attached segment" style="padding: 2em 3em;padding-bottom: 7rem;"> | |||
<div class="ui form" id="form_image"> | |||
{{.CsrfTokenHtml}} | |||
<div class="inline field"> | |||
<label class="label_color" for="">{{$.i18n.Tr "dataset.dataset_available_clusters"}}</label> | |||
<div class="ui basic label" style="border: none !important;color:#3291f8;"> | |||
<svg class="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="14" height="14"><path fill="none" d="M0 0h24v24H0z"></path><path d="M4 3h16a1 1 0 0 1 1 1v7H3V4a1 1 0 0 1 1-1zM3 13h18v7a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1v-7zm4 3v2h3v-2H7zM7 6v2h3V6H7z"></path></svg> | |||
{{if eq .Type 2}} | |||
{{$.i18n.Tr "cloudbrain.resource_cluster_c2net_simple"}} GPU | |||
{{else}} | |||
{{$.i18n.Tr "cloudbrain.resource_cluster_openi_simple"}} GPU | |||
{{end}} | |||
</div> | |||
<input type="hidden" value="{{.Type}}" name="type"> | |||
</div> | |||
<div class="inline required field"> | |||
<label class="label_color" for="">{{$.i18n.Tr "repo.images.name"}}</label> | |||
<input type="text" name="tag" required placeholder="{{$.i18n.Tr "repo.images.name_placerholder"}}" style="width: 80%;" maxlength="{{if eq .Type 2}} 50 {{else}} 100 {{end}}"> | |||
<span class="tooltips" style="display: block;padding-left: 1.5rem;"> | |||
{{if eq .Type 2}} | |||
{{.i18n.Tr "repo.images.name_rule50"}} | |||
{{else}} | |||
{{.i18n.Tr "repo.images.name_rule100"}} | |||
{{end}} | |||
</span> | |||
</div> | |||
<div class="inline required field"> | |||
<label class="label_color" for="">{{$.i18n.Tr "dataset.description"}}</label> | |||
<textarea style="width: 80%;" required id="description" name="description" rows="3" maxlength="1000" placeholder={{.i18n.Tr "repo.images.descr_placerholder"}} onchange="this.value=this.value.substring(0, 1000)" onkeydown="this.value=this.value.substring(0, 1000)" onkeyup="this.value=this.value.substring(0, 1000)"></textarea> | |||
</div> | |||
<div class="inline field" style="display: flex;align-items: center;"> | |||
<label class="label_color" for="">{{$.i18n.Tr "repo.model.manage.label"}}</label> | |||
<div class="ui multiple search selection dropdown" id="dropdown_image" style="width: 80%;"> | |||
<input type="hidden" name="topics" value="" required> | |||
<div class="default text" id="default_text">{{.i18n.Tr "repo.repo_label_helpe"}}</div> | |||
<div class="menu" id="course_label_item"></div> | |||
</div> | |||
</div> | |||
<span class="tooltips" style="display: block;padding-left: 1.5rem;margin-top: 0.5rem;margin-bottom: 1rem;">{{.i18n.Tr "repo.image.label_tooltips"}}</span> | |||
<!-- | |||
<div class="inline fields"> | |||
<label class="label_color" for="" style="visibility: hidden;"></label> | |||
<div class="field"> | |||
<div class="ui radio checkbox"> | |||
<input type="radio" name="isPrivate" checked="checked" value="false"> | |||
<label>{{.i18n.Tr "org.settings.visibility.public"}}</label> | |||
</div> | |||
</div> | |||
<div class="field" style="flex: 0.15;"> | |||
<div class="ui radio checkbox" > | |||
<input type="radio" name="isPrivate" value="true"> | |||
<label>{{.i18n.Tr "home.show_private"}}</label> | |||
</div> | |||
</div> | |||
<div class="field"> | |||
<span class="label_color">{{.i18n.Tr "repo.images.public_tooltips"}}</span> | |||
</div> | |||
</div> | |||
--> | |||
<div class="inline required field"> | |||
<label class="label_color" for="" style="visibility: hidden;"></label> | |||
<span style="color: rgb(255, 94, 0);display: inline-flex;"><i class="ri-error-warning-line" style="margin-right: 0.3rem;"></i>{{.i18n.Tr "repo.images.submit_tooltips"}}</span> | |||
</div> | |||
<div class="inline required field"> | |||
<label class="label_color" for="" style="visibility: hidden;"></label> | |||
<button class="ui create_image green button" type="button"> | |||
{{.i18n.Tr "repo.cloudbrain.commit_image"}} | |||
</button> | |||
<a class="ui button" id="cancel_submit_image">{{.i18n.Tr "repo.cloudbrain.cancel"}}</a> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
<!-- 确认模态框 --> | |||
<div> | |||
<div class="ui modal image_confirm_submit"> | |||
<div class="header">{{.i18n.Tr "repo.submit_image"}}</div> | |||
<div class="content text red center"> | |||
<p><i class="exclamation icon"></i>{{.i18n.Tr "repo.image_overwrite"}}</p> | |||
</div> | |||
<div class="actions"> | |||
<button class="ui deny small button">{{.i18n.Tr "cloudbrain.operate_cancel"}}</button> | |||
<button class="ui green small approve button">{{.i18n.Tr "cloudbrain.operate_confirm"}}</button> | |||
</div> | |||
</div> | |||
<script> | |||
window._PageType = "submit"; | |||
window._Image = {{.Image}}; | |||
window._ImageType = {{.Type}}; | |||
window._ImageComputeResource = {{.ComputeResource}}; | |||
window._PageFrom = "submit"; | |||
window._PageSubmitLink = {{$.Link}}; | |||
window._PageRepoLink = {{$.RepoLink}}; | |||
</script> | |||
<link rel="stylesheet" href="{{StaticUrlPrefix}}/css/vp-images-submit.css?v={{MD5 AppVer}}" /> | |||
<div id="__vue-root"></div> | |||
<script src="{{StaticUrlPrefix}}/js/vp-images-submit.js?v={{MD5 AppVer}}"></script> | |||
</div> | |||
{{template "base/footer" .}} |
@@ -111,12 +111,6 @@ | |||
<td class="t-center"><span class="typ">累计</span>积分获取上限<span class="limit"> - </span></td> | |||
<td>邀请好友获得积分。</td> | |||
</tr> | |||
<tr key="TaskInviteFriendRegister"> | |||
<td class="t-center">邀请好友</td> | |||
<td class="t-center point">-</td> | |||
<td class="t-center"><span class="typ">累计</span>积分获取上限<span class="limit"> - </span></td> | |||
<td>邀请好友获得积分。</td> | |||
</tr> | |||
</table> | |||
</div> | |||
@@ -222,7 +222,6 @@ func Generate(options ...Options) macaron.Handler { | |||
needsNew = true | |||
} | |||
} | |||
if needsNew { | |||
// FIXME: actionId. | |||
x.Token = GenerateToken(x.Secret, x.ID, "POST") | |||
@@ -90,7 +90,6 @@ func validTokenAtTime(token, key, userID, actionID string, now time.Time) bool { | |||
} | |||
expected := generateTokenAtTime(key, userID, actionID, issueTime) | |||
// Check that the token matches the expected value. | |||
// Use constant time comparison to avoid timing attacks. | |||
return subtle.ConstantTimeCompare([]byte(token), []byte(expected)) == 1 | |||
@@ -15,18 +15,7 @@ | |||
<div class="ui ten wide column" style="margin: 1rem 0;"> | |||
<el-checkbox v-model="checked" style="padding: 0.5rem 1rem;">{{ | |||
$i18n['cloudeBrainMirror']['platform_recommendations'] }}</el-checkbox> | |||
<!-- <el-dropdown @command="handleCommand" trigger="click" | |||
style="border: 1px solid rgba(34,36,38,.15);border-radius: 4px;padding: 0.5rem 1rem;"> | |||
<span class="el-dropdown-link"> | |||
{{dropdownPrivate}}<i class="el-icon-caret-bottom el-icon--right"></i> | |||
</span> | |||
<el-dropdown-menu slot="dropdown"> | |||
<el-dropdown-item :command="{label:$i18n['all'],private:''}">{{$i18n['all']}}</el-dropdown-item> | |||
<el-dropdown-item :command="{label:$i18n['cloudeBrainMirror']['public'],private:false}">{{$i18n['cloudeBrainMirror']['public']}}</el-dropdown-item> | |||
<el-dropdown-item :command="{label:$i18n['cloudeBrainMirror']['private'],private:true}">{{$i18n['cloudeBrainMirror']['private']}}</el-dropdown-item> | |||
</el-dropdown-menu> | |||
</el-dropdown> --> | |||
<el-dropdown @command="handleCommandType" trigger="click" | |||
<!-- <el-dropdown @command="handleCommandType" trigger="click" | |||
style="border: 1px solid rgba(34,36,38,.15);border-radius: 4px;padding: 0.5rem 1rem;"> | |||
<span class="el-dropdown-link"> | |||
{{ dropdownType }}<i class="el-icon-caret-bottom el-icon--right"></i> | |||
@@ -39,6 +28,28 @@ | |||
<el-dropdown-item :command="{ label: $i18n['cloudeBrainMirror']['c2net'], type: 2 }">{{ | |||
$i18n['cloudeBrainMirror']['c2net'] }}</el-dropdown-item> | |||
</el-dropdown-menu> | |||
</el-dropdown> --> | |||
<el-dropdown @command="handleCommandComputeResource" trigger="click" | |||
style="border: 1px solid rgba(34,36,38,.15);border-radius: 4px;padding: 0.5rem 1rem;"> | |||
<span class="el-dropdown-link"> | |||
{{ dropdownComputeResource }}<i class="el-icon-caret-bottom el-icon--right"></i> | |||
</span> | |||
<el-dropdown-menu slot="dropdown"> | |||
<el-dropdown-item :command="{ label: $i18n['cloudeBrainMirror']['all_compute_resource'], type: '' }">{{ | |||
$i18n['cloudeBrainMirror']['all_compute_resource'] }}</el-dropdown-item> | |||
<el-dropdown-item :command="{ label: $i18n['computeResourceTitle']['GPU'], type: 'GPU' }">{{ | |||
$i18n['computeResourceTitle']['GPU'] }}</el-dropdown-item> | |||
<el-dropdown-item :command="{ label: $i18n['computeResourceTitle']['GCU'], type: 'GCU' }">{{ | |||
$i18n['computeResourceTitle']['GCU'] }}</el-dropdown-item> | |||
<el-dropdown-item :command="{ label: $i18n['computeResourceTitle']['MLU'], type: 'MLU' }">{{ | |||
$i18n['computeResourceTitle']['MLU'] }}</el-dropdown-item> | |||
<el-dropdown-item | |||
:command="{ label: $i18n['computeResourceTitle']['ILUVATAR-GPGPU'], type: 'ILUVATAR-GPGPU' }">{{ | |||
$i18n['computeResourceTitle']['ILUVATAR-GPGPU'] }}</el-dropdown-item> | |||
<el-dropdown-item | |||
:command="{ label: $i18n['computeResourceTitle']['METAX-GPGPU'], type: 'METAX-GPGPU' }">{{ | |||
$i18n['computeResourceTitle']['METAX-GPGPU'] }}</el-dropdown-item> | |||
</el-dropdown-menu> | |||
</el-dropdown> | |||
<el-dropdown @command="handleApplyState" trigger="click" | |||
style="border: 1px solid rgba(34,36,38,.15);border-radius: 4px;padding: 0.5rem 1rem;"> | |||
@@ -80,17 +91,16 @@ | |||
$i18n['cloudeBrainMirror']['create_cloud_brain_mirror'] }}</a> | |||
</div> | |||
<div class="ui sixteen wide column" style="padding: 0;overflow-x:auto;"> | |||
<el-table :data="tableDataCustom" style="width: 100%;min-width:1700px;" :header-cell-style="tableHeaderStyle"> | |||
<el-table-column :label="$i18n['cloudeBrainMirror']['mirror_tag']" min-width="19%" align="left" prop="tag"> | |||
<el-table :data="tableDataCustom" style="min-width:100%;" :header-cell-style="tableHeaderStyle"> | |||
<el-table-column :label="$i18n['cloudeBrainMirror']['mirror_tag']" width="250px" align="left" prop="tag"> | |||
<template slot-scope="scope"> | |||
<div style="display: flex;align-items: center;"> | |||
<a class="text-over image_title" :title="scope.row.tag">{{ scope.row.tag }}</a> | |||
<!-- <i class="ri-lock-2-line" style="color: #fa8c16;padding: 0 1rem;" v-if="scope.row.isPrivate"></i> --> | |||
<img v-if="scope.row.type == 5" src="/img/jian.svg" style="margin-left: 0.5rem;"> | |||
</div> | |||
</template> | |||
</el-table-column> | |||
<el-table-column :label="$i18n['cloudeBrainMirror']['mirror_description']" min-width="26%" align="left" | |||
<el-table-column :label="$i18n['cloudeBrainMirror']['mirror_description']" width="300px" align="left" | |||
prop="description"> | |||
<template slot-scope="scope"> | |||
<div class="image_desc" :title="scope.row.description">{{ scope.row.description }} | |||
@@ -101,20 +111,48 @@ | |||
</div> | |||
</template> | |||
</el-table-column> | |||
<el-table-column prop="cloudbrainType" :label="$i18n['cloudeBrainMirror']['available_clusters']" | |||
min-width="10%" align="center"> | |||
<el-table-column :label="$i18n['model_compute_resource']" width="150px" align="left" | |||
prop="compute_resource"> | |||
<template slot-scope="scope"> | |||
{{ scope.row.cloudbrainType | transformType(vm) }} | |||
<span :title="scope.row.compute_resource">{{ $i18n['computeResourceTitle'][scope.row.compute_resource] | |||
|| scope.row.compute_resource }}</span> | |||
</template> | |||
</el-table-column> | |||
<!-- <el-table-column prop="isPrivate" :label="$i18n['cloudeBrainMirror']['state']" min-width="6%" align="center"> | |||
<el-table-column :label="$i18n['cloudeBrainMirror']['framework']" width="150px" align="left" | |||
prop="framework"> | |||
<template slot-scope="scope"> | |||
<span v-if="scope.row.isPrivate" style="color: rgb(250, 140, 22);">{{$i18n['cloudeBrainMirror']['private']}}</span> | |||
<span v-else style="color: rgb(19, 194, 141);">{{$i18n['cloudeBrainMirror']['public']}}</span> | |||
{{ scope.row.framework }}<br />{{ scope.row.frameworkVersion }} | |||
</template> | |||
</el-table-column> | |||
<el-table-column :label="'Python'" width="100px" align="left" prop="python"> | |||
<template slot-scope="scope"> | |||
{{ scope.row.pythonVersion }} | |||
</template> | |||
</el-table-column> | |||
<el-table-column :label="'Cuda'" width="100px" align="left" prop="cudaVersion"> | |||
<template slot-scope="scope"> | |||
{{ scope.row.cudaVersion || '--' }} | |||
</template> | |||
</el-table-column> | |||
<el-table-column :label="$i18n['cloudeBrainMirror']['operationSystem']" width="180px" align="left" | |||
prop="python"> | |||
<template slot-scope="scope"> | |||
{{ scope.row.operationSystem }}<br />{{ scope.row.operationSystemVersion }} | |||
</template> | |||
</el-table-column> | |||
<el-table-column :label="$i18n['cloudeBrainMirror']['thirdPackages']" width="220px" align="left" | |||
prop="thirdpackages"> | |||
<template slot-scope="scope"> | |||
<div class="image_desc" :title="scope.row.thirdPackages">{{ scope.row.thirdPackages }}</div> | |||
</template> | |||
</el-table-column> | |||
<!-- <el-table-column prop="cloudbrainType" :label="$i18n['cloudeBrainMirror']['available_clusters']" | |||
width="120px" align="center"> | |||
<template slot-scope="scope"> | |||
{{ scope.row.cloudbrainType | transformType(vm) }} | |||
</template> | |||
</el-table-column> --> | |||
<el-table-column prop="creator" :label="$i18n['cloudeBrainMirror']['creator']" min-width="6%" | |||
align="center"> | |||
<el-table-column prop="creator" :label="$i18n['cloudeBrainMirror']['creator']" width="80px" align="center"> | |||
<template slot-scope="scope"> | |||
<a v-if="scope.row.userName || scope.row.relAvatarLink" :href="'/' + scope.row.userName" | |||
:title="scope.row.userName"> | |||
@@ -126,13 +164,13 @@ | |||
</template> | |||
</el-table-column> | |||
<el-table-column prop="createdUnix" :label="$i18n['cloudeBrainMirror']['creation_time']" align="center" | |||
min-width="11%"> | |||
width="160px"> | |||
<template slot-scope="scope"> | |||
{{ scope.row.createdUnix | transformTimestamp }} | |||
</template> | |||
</el-table-column> | |||
<el-table-column prop="apply_status" :label="$i18n['cloudeBrainMirror']['approval_status']" min-width="10%" | |||
align="center"> | |||
<el-table-column prop="apply_status" :label="$i18n['cloudeBrainMirror']['approval_status']" width="120px" | |||
fixed="right" align="center"> | |||
<template slot-scope="scope"> | |||
<span v-if="scope.row.apply_status == 0" style="">{{ '--' }}</span> | |||
<div v-if="scope.row.apply_status === 1" | |||
@@ -168,7 +206,8 @@ | |||
</div> | |||
</template> | |||
</el-table-column> | |||
<el-table-column align="center" min-width="33%" :label="$i18n['cloudeBrainMirror']['operation']"> | |||
<el-table-column align="center" width="400px" :label="$i18n['cloudeBrainMirror']['operation']" | |||
fixed="right"> | |||
<template slot-scope="scope"> | |||
<div style="display: flex;justify-content: center;align-items: center;"> | |||
<div style="display: flex;align-items: center;padding: 0 1rem;" :title="$i18n['citations']"> | |||
@@ -253,6 +292,7 @@ export default { | |||
search: '', | |||
dropdownPrivate: '', | |||
dropdownType: '', | |||
dropdownComputeResource: '', | |||
dropdownApplyState: '', | |||
checked: false, | |||
currentPageCustom: 1, | |||
@@ -389,6 +429,12 @@ export default { | |||
this.paramsCustom.page = 1 | |||
this.getImageListCustom() | |||
}, | |||
handleCommandComputeResource(command) { | |||
this.dropdownComputeResource = command.label | |||
this.paramsCustom.computeResource = command.type | |||
this.paramsCustom.page = 1 | |||
this.getImageListCustom() | |||
}, | |||
handleApplyState(command) { | |||
this.dropdownApplyState = command.label | |||
this.paramsCustom.apply = command.type | |||
@@ -470,6 +516,7 @@ export default { | |||
this.dropdownPrivate = this.$i18n['all']; | |||
this.dropdownType = this.$i18n['cloudeBrainMirror']['all_cluster']; | |||
this.dropdownApplyState = this.$i18n['cloudeBrainMirror']['all_approval_status']; | |||
this.dropdownComputeResource = this.$i18n['cloudeBrainMirror']['all_compute_resource']; | |||
let params = new URLSearchParams(location.search) | |||
if (location.search) { | |||
this.firstSearch = true | |||
@@ -483,6 +530,9 @@ export default { | |||
if (params.has('cloudbrainType')) { | |||
this.dropdownType = params.get('cloudbrainType') === 0 ? this.$i18n['cloudeBrainMirror']['openi'] : this.$i18n['cloudeBrainMirror']['c2net'] | |||
} | |||
if (params.has('computeResource')) { | |||
this.dropdownComputeResource = this.$i18n['computeResourceTitle'][params.get('computeResource')]; | |||
} | |||
if (params.has('apply')) { | |||
const apply = params.get('apply'); | |||
switch (apply) { | |||
@@ -201,6 +201,10 @@ export const i18nVue = { | |||
not_recommend: '不同意推荐', | |||
reason: '原因', | |||
pleaseEnterReason: '请输入原因', | |||
framework: '框架', | |||
operationSystem: '操作系统', | |||
thirdPackages: 'Python依赖库', | |||
all_compute_resource: '全部计算资源', | |||
}, | |||
modelObj: { | |||
model_label: '选择模型', | |||
@@ -223,7 +227,17 @@ export const i18nVue = { | |||
export_success: '导出成功', | |||
exporting: '正在导出', | |||
please_select_file:'请先选择文件', | |||
} | |||
}, | |||
computeResourceTitle: { | |||
'CPU/GPU': '英伟达GPU', | |||
GPU: '英伟达GPU', | |||
NPU: '昇腾NPU', | |||
GCU: '燧原GCU', | |||
MLU: '寒武纪MLU', | |||
DCU: '海光DCU', | |||
'ILUVATAR-GPGPU': '天数智芯GPGPU', | |||
'METAX-GPGPU': '沐曦GPGPU', | |||
}, | |||
}, | |||
US: { | |||
computer_vision: "computer vision", | |||
@@ -383,10 +397,10 @@ export const i18nVue = { | |||
public_mirror: 'Public Mirror', | |||
recommendImages: 'Recommend Mirror', | |||
platform_recommendations:'Show platform recommendations only', | |||
placeholder: 'Search Mirror tag / description / tag ... ', | |||
placeholder: 'Search Mirror tag / description / label ... ', | |||
search:'Search', | |||
mirror_tag:'Mirror Tag', | |||
mirror_description:'mirror_description ', | |||
mirror_description:'Mirror Description ', | |||
available_clusters: 'Cluster/Compute Resources', | |||
creator: 'Creator', | |||
creation_time: 'Creation time', | |||
@@ -430,6 +444,10 @@ export const i18nVue = { | |||
not_recommend: 'Not recommend', | |||
reason: 'Reason', | |||
pleaseEnterReason: 'Please enter the reason', | |||
framework: 'Framework', | |||
operationSystem: 'Operating system', | |||
thirdPackages: 'Python libraries', | |||
all_compute_resource: 'All Compute Resource', | |||
}, | |||
modelObj: { | |||
model_label: 'Select Model', | |||
@@ -452,6 +470,16 @@ export const i18nVue = { | |||
export_success: 'Export success', | |||
exporting: ' Exporting', | |||
please_select_file: 'Please select a file first', | |||
} | |||
}, | |||
computeResourceTitle: { | |||
'CPU/GPU': 'NVIDIA GPU', | |||
GPU: 'NVIDIA GPU', | |||
NPU: 'Ascend NPU', | |||
GCU: 'Enflame GCU', | |||
MLU: 'Cambricon MLU', | |||
DCU: 'HYGON DCU', | |||
'ILUVATAR-GPGPU': 'Iluvatar CoreX GPGPU', | |||
'METAX-GPGPU': 'MetaX GPGPU', | |||
}, | |||
}, | |||
}; |
@@ -1,5 +1,14 @@ | |||
import service from '../service'; | |||
// 获取promote配置数据 | |||
export const getStaticFile = (filePathName) => { | |||
return service({ | |||
url: `${filePathName}`, | |||
method: 'get', | |||
params: {}, | |||
}); | |||
} | |||
// 获取promote配置数据 | |||
export const getPromoteData = (filePathName) => { | |||
return service({ | |||
@@ -1,7 +1,8 @@ | |||
import service from "../service"; | |||
import service from '../service'; | |||
import Qs from 'qs'; | |||
// 获取镜像 | |||
// params: { type-0|1|2, q, page, pageSize, cloudbrainType-0,1 } | |||
// params: { type-0|1|2, q, page, pageSize, cloudbrainType-0,1, sort, framework, frameworkVersion, cuda, python } | |||
export const getImages = (params) => { | |||
const typeMap = { | |||
'0': 'recommend', | |||
@@ -17,9 +18,69 @@ export const getImages = (params) => { | |||
method: "get", | |||
params: { | |||
q: params.q || '', | |||
cloudbrainType: params.cloudbrainType || '-1', | |||
sort: params.sort, | |||
computeResource: params.computeResource, | |||
framework: params.framework, | |||
frameworkVersion: params.frameworkVersion, | |||
cuda: params.cuda, | |||
python: params.python, | |||
spec: params.spec, | |||
trainType: params.trainType, | |||
page: params.page || 1, | |||
pageSize: params.pageSize || 5, | |||
cloudbrainType: params.cloudbrainType, | |||
} | |||
}); | |||
}; | |||
export const putImageAction = (params) => { | |||
return service({ | |||
url: `/image/${params.id}/action/${params.action}`, | |||
method: 'put', | |||
params: {} | |||
}); | |||
}; | |||
export const deleteImage = (params) => { | |||
return service({ | |||
url: `/image/${params.id}`, | |||
method: 'delete', | |||
params: {} | |||
}); | |||
}; | |||
export const submitImage = (data) => { | |||
return service({ | |||
url: data.link, | |||
method: 'post', | |||
params: {}, | |||
data: Qs.stringify(data), | |||
}); | |||
}; | |||
export const getImageById = (params) => { | |||
return service({ | |||
url: `/image/${params.id}`, | |||
method: 'get', | |||
params: {}, | |||
}); | |||
}; | |||
export const searchImageTopics = (params) => { | |||
return service({ | |||
url: `/api/v1/image/topics/search`, | |||
method: 'get', | |||
params: { q: params.q } | |||
}); | |||
}; | |||
// 查询选择镜像过滤条件 | |||
// params: index-查询类型:0(可用框架)|1(可用框架版本)|2(可用python版本)|3(可用cuda版本) | |||
// framework-框架,version-框架版本,python-python版本 | |||
export const getImageAvailabelFilter = (params) => { | |||
return service({ | |||
url: `/api/v1/images/availableFilter`, | |||
method: 'get', | |||
params: { ...params } | |||
}); | |||
}; |
@@ -115,7 +115,6 @@ export default { | |||
margin-left: -1px; | |||
height: 38px; | |||
padding: 0 12px; | |||
border-left: none; | |||
margin-bottom: 5px; | |||
i { | |||
@@ -6,7 +6,8 @@ | |||
</div> | |||
<div class="content" :class="errStatus ? 'error' : ''"> | |||
<el-input class="field-input" v-model="imageUrl" @input="imageChange" | |||
:placeholder="$t('cloudbrainObj.selectImagePlaceholder')"></el-input> | |||
:readonly="configs.computerResouce != 'GPU'" :placeholder="configs.computerResouce == 'GPU' ? | |||
$t('cloudbrainObj.selectImagePlaceholder') : $t('cloudbrainObj.selectImage')"></el-input> | |||
</div> | |||
</div> | |||
<div class="right-area"> | |||
@@ -16,8 +17,8 @@ | |||
</div> | |||
</div> | |||
<el-dialog class="model-dlg" :visible.sync="dlgShow" :title="$t('cloudbrainObj.selectImage')" width="1000px" | |||
:modal="true" :close-on-click-modal="false" :show-close="true" :destroy-on-close="false" :before-close="beforeClose" | |||
@open="open" @closed="closed"> | |||
:modal="true" :close-on-click-modal="false" :show-close="true" :destroy-on-close="false" | |||
:before-close="beforeClose" @open="open" @closed="closed"> | |||
<div class="dlg-content"> | |||
<div class="main-area" v-loading="dlgLoading"> | |||
<div class="image-tabs-c"> | |||
@@ -26,9 +27,23 @@ | |||
<el-tab-pane :label="$t('cloudbrainObj.myImage')" name="second"></el-tab-pane> | |||
<el-tab-pane :label="$t('cloudbrainObj.myFavImage')" name="third"></el-tab-pane> | |||
</el-tabs> | |||
</div> | |||
<div class="filter-c"> | |||
<div class="cascader-c"> | |||
<span class="cascader-tit">{{ $t('imagesObj.filterImages') }}:</span> | |||
<div class="cascader-content-c"> | |||
<div class="cascader-tips">{{ filterImagesPlaceholder }}</div> | |||
<el-cascader class="image-filter" ref="cascaderFilterRef" v-model="dlgCascaderFilter.value" | |||
:props="dlgCascaderProps" :options="dlgCascaderFilter.options" clearable | |||
:placeholder="$t('imagesObj.filterImages')" :popper-class="dlgCascaderFilter.popperClass" | |||
@expand-change="handleDlgCascaderFilterExpandChange" | |||
@visible-change="handleDlgCascaderFilterVisibleChange" | |||
@change="handleDlgCascaderFilterChange"></el-cascader> | |||
</div> | |||
</div> | |||
<el-input size="small" class="search-inp" :placeholder="$t('cloudbrainObj.searchImagePlaceholder')" | |||
v-model="dlgSearchValue" @keydown.enter.stop.native.prevent="inputSearch"> | |||
<div slot="suffix" class="search-inp-icon" @click="inputSearch"> | |||
v-model="dlgSearchValue" @keydown.enter.stop.native.prevent="search"> | |||
<div slot="suffix" class="search-inp-icon" @click="search"> | |||
<i class="el-icon-search"></i> | |||
</div> | |||
</el-input> | |||
@@ -41,15 +56,29 @@ | |||
<span :title="item.tag">{{ item.tag }}</span> | |||
<img v-if="item.type == 5" src="/img/jian.svg" /> | |||
</div> | |||
<div></div> | |||
</div> | |||
<div class="item-l-m"> | |||
<div class="item-topics"> | |||
<span class="type-compute-resource" | |||
:style="item.computeResourceColor ? `background-color: ${item.computeResourceColor};` : ''">{{ | |||
item.computeResourceShow }}</span> | |||
<span class="type-sys" v-for="(topic, index) in item.topicsSys" :key="`sys-${index}`">{{ topic | |||
}}</span> | |||
<span class="type-pkg" v-for="(topic, index) in item.topicsPkg" :key="`pkg-${index}`">{{ topic | |||
}}</span> | |||
<span v-for="(topic, index) in item.topics" :key="index">{{ topic }}</span> | |||
</div> | |||
</div> | |||
<div class="item-l-b"> | |||
<a class="item-creator" :href="`/${item.userName}`"> | |||
<a v-if="item.userName" class="item-creator" :href="`/${item.userName}`"> | |||
<img class="ui avatar mini image" style="width: 20px; height: 20px" | |||
:src="item.relAvatarLink ? item.relAvatarLink : `/user/avatar/ghost/-1`" /> | |||
</a> | |||
<a v-else class="item-creator" href="javascript:;"> | |||
<img class="ui avatar mini image" style="width: 20px; height: 20px" | |||
:src="`/user/avatar/ghost/-1`" /> | |||
</a> | |||
<span class="item-descr" :title="item.description">{{ item.description }}</span> | |||
</div> | |||
</div> | |||
@@ -81,15 +110,19 @@ | |||
</template> | |||
<script> | |||
import { getImages } from '~/apis/modules/images'; | |||
import { getImages, getImageAvailabelFilter } from '~/apis/modules/images'; | |||
import { COMPUTER_RESOURCES_COLORS, JOB_TYPE } from '~/const'; | |||
import { getListValueWithKey } from '~/utils'; | |||
export default { | |||
name: "ImageSelectV1", | |||
props: { | |||
value: { type: String, required: true }, | |||
type: { type: Number, default: 0 }, | |||
type: { type: Number, default: 0 }, // -1-全部,0-启智GPU,2-智算GPU | |||
showTitle: { type: Boolean, default: true }, | |||
required: { type: Boolean, default: true }, | |||
spec: { type: String, required: true, }, | |||
configs: { type: Object, default: () => ({}) }, | |||
}, | |||
data() { | |||
return { | |||
@@ -100,7 +133,38 @@ export default { | |||
dlgLoading: false, | |||
dlgActiveName: 'first', | |||
dlgSearchValue: '', | |||
dlgCascaderFilter: { | |||
popperClass: `popper-filter-${Math.random().toString().replace('.', '')}`, | |||
value: [], | |||
options: [] | |||
}, | |||
dlgCascaderProps: { | |||
lazy: true, | |||
lazyLoad: (node, resolve) => { | |||
const { level } = node; | |||
const framework = node.path[0]; | |||
const version = node.path[1]; | |||
const python = node.path[2]; | |||
getImageAvailabelFilter({ index: level, framework, version, python }).then(res => { | |||
if (res.data.code == 0) { | |||
const nodes = (res.data.data).map(item => ({ | |||
value: item, | |||
label: item ? item : 'None', | |||
leaf: level >= (this.configs.computerResouce == 'GPU' ? 3 : 2) | |||
})); | |||
if (!nodes.length) { | |||
node.config.leaf = true; | |||
} | |||
resolve(nodes); | |||
} else { | |||
resolve([]); | |||
} | |||
}).catch(err => { | |||
console.log(err); | |||
resolve([]); | |||
}); | |||
} | |||
}, | |||
dlgPage: 1, | |||
dlgPageSize: 5, | |||
dlgTotal: 0, | |||
@@ -116,6 +180,21 @@ export default { | |||
this.imageUrl = newVal.toString(); | |||
this.$emit('input', newVal); | |||
} | |||
}, | |||
spec: { | |||
immediate: true, | |||
handler(newVal) { | |||
this.$emit('changeImage'); | |||
} | |||
}, | |||
}, | |||
computed: { | |||
filterImagesPlaceholder() { | |||
const list = this.$t('imagesObj.filterImagesPlaceholder').split('/'); | |||
if (this.configs.computerResouce != 'GPU') { | |||
list.pop(); | |||
} | |||
return list.join('/'); | |||
} | |||
}, | |||
methods: { | |||
@@ -135,11 +214,49 @@ export default { | |||
this.dlgPage = 1; | |||
this.searchImageData(); | |||
}, | |||
inputSearch() { | |||
search() { | |||
this.dlgTotal = 0; | |||
this.dlgPage = 1; | |||
this.searchImageData(); | |||
}, | |||
handleDlgCascaderFilterVisibleChange() { | |||
const popper = document.querySelector(`.${this.dlgCascaderFilter.popperClass}`); | |||
if (popper && popper.querySelector('.popper-filter-title')) return; | |||
const title = document.createElement('div'); | |||
title.classList = ['popper-filter-title']; | |||
title.style = 'display:flex;margin-left:-1px;'; | |||
let innerHtml = ''; | |||
const titles = [ | |||
this.$t('imagesObj.frameworkName'), this.$t('imagesObj.frameworkVersion'), | |||
this.$t('imagesObj.pyVersion'), this.$t('imagesObj.cudaVersion') | |||
]; | |||
if (this.configs.computerResouce != 'GPU') { | |||
titles.pop(); | |||
} | |||
titles.forEach((item, index) => { | |||
innerHtml += `<div class="popper-filter-title-item" | |||
style="display:flex;align-items:center;height:30px;width:180px;box-sizing:border-box;color:rgb(136, 136, 136); | |||
${index != 0 ? 'border-left:1px solid #E4E7ED;display:none;' : ''}padding-top:10px;padding-left:30px;font-size:12px;">${item}</div>`; | |||
}) | |||
title.innerHTML = innerHtml; | |||
popper.prepend(title); | |||
}, | |||
handleDlgCascaderFilterExpandChange(value) { | |||
const popper = document.querySelector(`.${this.dlgCascaderFilter.popperClass}`); | |||
const title = popper.querySelector('.popper-filter-title'); | |||
const items = title.querySelectorAll('.popper-filter-title-item'); | |||
items.forEach((item, index) => { | |||
const style = item.style; | |||
if (index <= value.length) { | |||
style.display = 'flex'; | |||
} else { | |||
style.display = 'none'; | |||
} | |||
}) | |||
}, | |||
handleDlgCascaderFilterChange() { | |||
this.search(); | |||
}, | |||
searchImageData() { | |||
const tabName = this.dlgActiveName; | |||
const typeMap = { | |||
@@ -153,11 +270,45 @@ export default { | |||
page: this.dlgPage, | |||
pageSize: this.dlgPageSize, | |||
cloudbrainType: this.type, | |||
computeResource: this.configs.computerResouce, | |||
framework: this.dlgCascaderFilter.value[0], | |||
frameworkVersion: this.dlgCascaderFilter.value[1], | |||
python: this.dlgCascaderFilter.value[2], | |||
cuda: this.dlgCascaderFilter.value[3], | |||
spec: this.configs.computerResouce == 'GPU' ? -1 : this.spec, | |||
trainType: this.configs.computerResouce == 'GPU' ? undefined : getListValueWithKey(JOB_TYPE, this.configs.taskType, 'k', 'train_type'), | |||
} | |||
this.dlgLoading = true; | |||
getImages(params).then(res => { | |||
this.dlgLoading = false; | |||
const data = res.data?.images || []; | |||
data.forEach(item => { | |||
const topicsSys = []; | |||
if (item.framework) { | |||
topicsSys.push(`${item.framework} ${item.frameworkVersion}`.trim()); | |||
} | |||
if (item.pythonVersion) { | |||
topicsSys.push(`Python ${item.pythonVersion}`); | |||
} | |||
if (item.cudaVersion) { | |||
topicsSys.push(`Cuda ${item.cudaVersion}`); | |||
} | |||
if (item.operationSystem) { | |||
topicsSys.push(`${item.operationSystem} ${item.operationSystemVersion}`.trim()); | |||
} | |||
const topicsPkg = []; | |||
const thirdPackages = item.thirdPackages.split('\n'); | |||
thirdPackages.forEach(pkgLine => { | |||
if (pkgLine) { | |||
topicsPkg.push(pkgLine.trim().replace('==', ' ')); | |||
} | |||
}); | |||
item.topicsSys = topicsSys; | |||
item.topicsPkg = topicsPkg; | |||
const compute_resource = item.compute_resource || 'GPU'; | |||
item.computeResourceColor = COMPUTER_RESOURCES_COLORS[compute_resource]; | |||
item.computeResourceShow = this.$t('computeResourceTitle.' + compute_resource); | |||
}); | |||
this.imageList = data; | |||
this.dlgTotal = parseInt(res.data?.count || 0); | |||
}).catch(err => { | |||
@@ -192,7 +343,24 @@ export default { | |||
return !this.errStatus; | |||
}, | |||
}, | |||
beforeMount() { }, | |||
beforeMount() { | |||
getImageAvailabelFilter({ index: 0 }).then(res => { | |||
if (res.data.code == 0) { | |||
let data = res.data.data || []; | |||
if (data.indexOf('Other') >= 0) { | |||
data = data.filter(item => item !== 'Other'); | |||
data.push('Other'); | |||
} | |||
this.dlgCascaderFilter.options = data.map(item => ({ | |||
value: item, | |||
label: item, | |||
leaf: item == 'Other' ? true : false, | |||
})); | |||
} | |||
}).catch(err => { | |||
console.log(err); | |||
}) | |||
}, | |||
mounted() { }, | |||
}; | |||
</script> | |||
@@ -242,13 +410,40 @@ export default { | |||
overflow: hidden; | |||
margin-right: 5px; | |||
} | |||
} | |||
.filter-c { | |||
display: flex; | |||
align-items: flex-end; | |||
justify-content: space-between; | |||
.cascader-c { | |||
display: flex; | |||
align-items: flex-end; | |||
.cascader-tit { | |||
margin-bottom: 6px; | |||
} | |||
.cascader-content-c { | |||
.cascader-tips { | |||
font-size: 12px; | |||
padding-left: 16px; | |||
} | |||
} | |||
} | |||
.image-filter { | |||
margin-top: -1px; | |||
width: 340px; | |||
} | |||
.search-inp { | |||
overflow: hidden; | |||
width: 200px; | |||
width: 330px; | |||
z-index: 5; | |||
position: relative; | |||
margin-top: -10px; | |||
margin-top: -1px; | |||
.search-inp-icon { | |||
height: 100%; | |||
@@ -299,14 +494,19 @@ export default { | |||
vertical-align: middle; | |||
} | |||
} | |||
} | |||
.item-l-m { | |||
margin-top: 4px; | |||
.item-topics { | |||
display: inline-block; | |||
overflow: hidden; | |||
text-overflow: ellipsis; | |||
white-space: nowrap; | |||
display: flex; | |||
flex-wrap: wrap; | |||
span { | |||
display: flex; | |||
align-items: center; | |||
justify-content: center; | |||
font-size: .85714286rem; | |||
margin: 0 0.14285714em; | |||
padding: 0.3em 0.5em; | |||
@@ -314,8 +514,21 @@ export default { | |||
color: rgba(0, 0, 0, .6); | |||
font-weight: 700; | |||
border-radius: 0.28571429rem; | |||
line-height: 1; | |||
cursor: pointer; | |||
line-height: 1; | |||
margin-bottom: 3px; | |||
&.type-sys { | |||
background: rgba(50, 145, 248, 0.2); | |||
} | |||
&.type-pkg { | |||
background: rgba(91, 185, 115, 0.2); | |||
} | |||
&.type-compute-resource { | |||
color: white; | |||
} | |||
} | |||
} | |||
} | |||
@@ -6,12 +6,25 @@ export const POINT_ACTIONS = [ | |||
{ k: 'CreatePublicRepo', v: i18n.t('createPublicProject') }, { k: 'CreateIssue', v: i18n.t('dailyPutforwardTasks') }, { k: 'CreatePullRequest', v: i18n.t('dailyPR') }, { k: 'CommentIssue', v: i18n.t('comment') }, { k: 'UploadAttachment', v: i18n.t('uploadDatasetFile') }, { k: 'CreateNewModelTask', v: i18n.t('importNewModel') }, { k: 'BindWechat', v: i18n.t('completeWechatCodeScanningVerification') }, | |||
{ k: 'CreateCloudbrainTask', v: i18n.t('dailyRunCloudbrainTasks') }, { k: 'DatasetRecommended', v: i18n.t('datasetRecommendedByThePlatform') }, { k: 'CreateImage', v: i18n.t('submitNewPublicImage') }, { k: 'ImageRecommend', v: i18n.t('imageRecommendedByThePlatform') }, { k: 'ChangeUserAvatar', v: i18n.t('firstChangeofAvatar') }, { k: 'PushCommits', v: i18n.t('dailyCommit') }, { k: 'TaskInviteFriendRegister', v: i18n.t('user.inviteFriends') } | |||
]; | |||
export const JOB_TYPE = [{ k: 'DEBUG', v: i18n.t('debugTask') }, { k: 'TRAIN', v: i18n.t('trainTask') }, { k: 'INFERENCE', v: i18n.t('inferenceTask') }, { k: 'BENCHMARK', v: i18n.t('benchmarkTask') }, { k: 'ONLINEINFERENCE', v: i18n.t('onlineinfer') }, { k: 'HPC', v: i18n.t('superComputeTask') }]; | |||
export const JOB_TYPE = [ | |||
{ k: 'DEBUG', v: i18n.t('debugTask'), train_type: 'Notebook' }, | |||
{ k: 'TRAIN', v: i18n.t('trainTask'), train_type: 'TrainJob' }, | |||
{ k: 'INFERENCE', v: i18n.t('inferenceTask'), train_type: 'Inference' }, | |||
{ k: 'BENCHMARK', v: i18n.t('benchmarkTask') }, | |||
{ k: 'ONLINEINFERENCE', v: i18n.t('onlineinfer') }, | |||
{ k: 'HPC', v: i18n.t('superComputeTask') } | |||
]; | |||
// 资源管理 | |||
export const CLUSTERS = [{ k: 'OpenI', v: i18n.t('resourcesManagement.OpenI') }, { k: 'C2Net', v: i18n.t('resourcesManagement.C2Net') }]; | |||
export const AI_CENTER = [{ k: 'OpenIOne', v: i18n.t('resourcesManagement.OpenIOne') }, { k: 'OpenITwo', v: i18n.t('resourcesManagement.OpenITwo') }, { k: 'OpenIChengdu', v: i18n.t('resourcesManagement.OpenIChengdu') }, { k: 'pclcci', v: i18n.t('resourcesManagement.pclcci') }, { k: 'hefei', v: i18n.t('resourcesManagement.hefeiCenter') }, { k: 'xuchang', v: i18n.t('resourcesManagement.xuchangCenter') }]; | |||
export const COMPUTER_RESOURCES = [{ k: 'CPU', v: 'CPU' }, { k: 'GPU', v: 'GPU' }, { k: 'NPU', v: 'NPU' }, { k: 'GCU', v: 'GCU' }, { k: 'MLU', v: 'MLU' }, { k: 'DCU', v: 'DCU' }, { k: 'ILUVATAR-GPGPU', v: 'ILUVATAR-GPGPU' }, { k: 'METAX-GPGPU', v: 'METAX-GPGPU' }]; | |||
export const COMPUTER_RESOURCES_COLORS = { | |||
'GPU': '#4fb62f', | |||
'GCU': '#e73828', | |||
'MLU': '#0077ed', | |||
'ILUVATAR-GPGPU': '#0038bd', | |||
'METAX-GPGPU': '#5c246a', | |||
}; | |||
export const ACC_CARD_TYPE = [{ k: 'T4', v: 'T4' }, { k: 'A100', v: 'A100' }, { k: 'V100', v: 'V100' }, { k: 'ASCEND910', v: 'Ascend 910' }, { k: 'ASCEND-D910B', v: 'Ascend-D910B' }, { k: 'MLU270', v: 'MLU270' }, { k: 'MLU290', v: 'MLU290' }, { k: 'RTX3080', v: 'RTX3080' }, { k: 'ENFLAME-T20', v: 'ENFLAME-T20' }, { k: 'DCU', v: 'DCU' }, { k: 'BI-V100', v: 'BI-V100' }, { k: 'MR-V100', v: 'MR-V100' }, { k: 'N100', v: 'N100' }]; | |||
export const SPECIFICATION_STATUS = [{ k: '1', v: i18n.t('resourcesManagement.willOnShelf') }, { k: '2', v: i18n.t('resourcesManagement.onShelf') }, { k: '3', v: i18n.t('resourcesManagement.offShelf') }]; | |||
export const NETWORK_TYPE = [{ k: 1, v: `${i18n.t('cloudbrainObj.networkType')}(${i18n.t('cloudbrainObj.noInternet')})` }, { k: 2, v: `${i18n.t('cloudbrainObj.networkType')}(${i18n.t('cloudbrainObj.hasInternet')})` }]; | |||
@@ -478,6 +478,61 @@ const en = { | |||
codeUseDlgTriggerTxt: 'How to use datasets in OpenI', | |||
codeUseDlgTitle: 'How to use datasets on the OpenI', | |||
}, | |||
imagesObj: { | |||
cloudbrain_images: 'Cloud Brain Mirror', | |||
openIGPU: 'OpenI GPU', | |||
c2netGPU: 'C2Net GPU', | |||
images_search: 'Search Mirror tag/description/operating system/python library/label...', | |||
image_public: 'Recommend Mirror', | |||
image_my: 'My Mirror', | |||
image_collected: 'Favorite Mirror', | |||
framework: 'Framework', | |||
version: 'Version', | |||
frameworkName: 'Framework name', | |||
frameworkVersion: 'Framework version', | |||
pyVersion: 'Python version', | |||
cudaVersion: 'Cuda version', | |||
deleteTips: 'Are you sure you want to delete this image? Once this image is deleted, it cannot be recovered.', | |||
deleteSuccessTips: 'Successfully deleted', | |||
editImage: 'Modify image', | |||
submitImage: 'Submit image', | |||
appyImage: 'Apply to become a platform recommended image', | |||
imageTag: 'Image tag', | |||
imageTagPlaceholder: 'Please enter the image tag', | |||
imageTagInputTips: 'Please enter letters, numbers, _ and -, with a maximum length of 50 characters and starting with a letter.', | |||
imageAdress: 'Image address', | |||
imageAdressPlaceholder: 'Please enter the image adress', | |||
imageAiCenterPlaceholder: 'Please enter the ai center. For example:\n[{"aiCenterId":"ai-center-id","imageUrl":"image-url","imageId":"image-id"}]', | |||
operationSystem: 'Operating system', | |||
operationSystemName: 'Operating system name', | |||
operationSystemNamePlaceholder: 'Please enter the operating system name', | |||
operationSystemVersionPlaceholder: 'Please enter the operating system version', | |||
pyPackge: 'Python libraries', | |||
thirdPackages: 'Python libraries and version', | |||
thirdPackagesPlaceholder: `Please enter the installed Python library and version, one per line, up to 10 lines. For example:\ntorch==1.13.1\ntransformers==4.25.1`, | |||
topic: 'Label', | |||
topicPlaceholder: 'After entering, press enter to confirm the label', | |||
topicTips: `Please provide additional information in the label field for the image, such as the compatible card type: <span class="light">T4</span>`, | |||
descr: 'Image description', | |||
descrPlaceholder: 'Please enter the image description, which should not exceed 1000 characters', | |||
recommend: 'Recommend', | |||
notRecommend: 'Unrecommend', | |||
submitTips: 'The code directory /tmp/code, dataset directory /tmp/dataset will not be submitted with the image, and other directories will be packaged into the image.', | |||
submitApply: 'Submit Apply', | |||
imageCommitting: 'Image committing...', | |||
imageCommitSuccess: 'Image committed successfully', | |||
imageCommitErrorTips: 'Check whether the size of the submitted image exceeds 20G!', | |||
committing: 'Commiting', | |||
commitSuccess: 'Committed successfully', | |||
commitFailed: 'Committed failed', | |||
recommendNeedReview: 'Pending approval', | |||
recommendReviewApproved: 'Approved', | |||
recommendReviewFailed: 'Not approved', | |||
applyForRecommend: 'Apply recommendation', | |||
copyAdress: 'Copy adress', | |||
filterImages: 'Filter images', | |||
filterImagesPlaceholder: 'Framework name/Framework version/Python version/Cuda version', | |||
}, | |||
specObj: { | |||
resSelectTips: 'The "resource specification" is the hardware you use to run the task. In order for more people to use the resources of this platform, please select according to your actual needs', | |||
no_use_resource: 'No resources available', | |||
@@ -637,7 +692,7 @@ const en = { | |||
recommendImage: 'Recommend Image', | |||
myImage: 'My Images', | |||
myFavImage: 'My collected images', | |||
searchImagePlaceholder: 'Search image tag/description/label...', | |||
searchImagePlaceholder: 'Search image tag/description/operating system/python library/label...', | |||
useImage: 'Use', | |||
submitting: 'Commiting', | |||
submitFailed: 'Commit failed', | |||
@@ -494,6 +494,61 @@ const zh = { | |||
codeUseDlgTriggerTxt: '在OpenI如何使用数据集', | |||
codeUseDlgTitle: '如何在OpenI协作平台使用数据集', | |||
}, | |||
imagesObj: { | |||
cloudbrain_images: '云脑镜像', | |||
openIGPU: '启智GPU', | |||
c2netGPU: '智算GPU', | |||
images_search: '搜镜像Tag/描述/操作系统/安装的软件包/标签', | |||
image_public: '平台推荐镜像', | |||
image_my: '我的镜像', | |||
image_collected: '我收藏的镜像', | |||
framework: '框架', | |||
version: '版本', | |||
frameworkName: '框架名称', | |||
frameworkVersion: '框架版本', | |||
pyVersion: 'Python版本', | |||
cudaVersion: 'Cuda版本', | |||
deleteTips: '你确认删除该镜像么?此镜像一旦删除不可恢复。', | |||
deleteSuccessTips: '删除成功', | |||
editImage: '修改镜像', | |||
submitImage: '提交镜像', | |||
appyImage: '申请成为平台推荐镜像', | |||
imageTag: '镜像Tag', | |||
imageTagPlaceholder: '请输入镜像Tag', | |||
imageTagInputTips: '请输入字母、数字、_和-,最长50个字符,且以字母开头。', | |||
imageAdress: '镜像地址', | |||
imageAdressPlaceholder: '请输入镜像地址', | |||
imageAiCenterPlaceholder: '请输入智算中心JSON格式,如:\n[{"aiCenterId":"ai-center-id","imageUrl":"image-url","imageId":"image-id"}]', | |||
operationSystem: '操作系统', | |||
operationSystemName: '操作系统名称', | |||
operationSystemNamePlaceholder: '请输入操作系统名称', | |||
operationSystemVersionPlaceholder: '请输入操作系统版本', | |||
pyPackge: 'Python依赖库', | |||
thirdPackages: 'Python依赖库及版本', | |||
thirdPackagesPlaceholder: `请输入安装的软件包及版本,一行一个,最多10行。如:\ntorch==1.13.1\ntransformers==4.25.1`, | |||
topic: '标签', | |||
topicPlaceholder: '输入完成后回车键完成标签确定', | |||
topicTips: `请在标签字段补充镜像中其他信息,如:适配的卡类型:<span class="light">T4</span>`, | |||
descr: '镜像简介', | |||
descrPlaceholder: '请输入镜像简介,不超过1000个字符', | |||
recommend: '推荐', | |||
notRecommend: '不推荐', | |||
submitTips: '代码目录/tmp/code,数据集目录/tmp/dataset不会随镜像提交,其他目录都会打包到镜像中。', | |||
submitApply: '提交申请', | |||
imageCommitting: '镜像提交中...', | |||
imageCommitSuccess: '镜像提交成功', | |||
imageCommitErrorTips: '检测提交镜像是否大小超过20G!', | |||
committing: '提交中', | |||
commitSuccess: '提交成功', | |||
commitFailed: '提交失败', | |||
recommendNeedReview: '推荐待审核', | |||
recommendReviewApproved: '通过推荐审核', | |||
recommendReviewFailed: '未通过推荐审核', | |||
applyForRecommend: '申请推荐', | |||
copyAdress: '复制地址', | |||
filterImages: '筛选镜像', | |||
filterImagesPlaceholder: '框架名称/框架版本/Python版本/Cuda版本', | |||
}, | |||
specObj: { | |||
resSelectTips: '「资源规格」是您运行该任务使用的硬件,为了更多人能够使用本平台的资源,请按照您的实际需求进行选择。', | |||
no_use_resource: '暂无可用资源' | |||
@@ -652,7 +707,7 @@ const zh = { | |||
recommendImage: '平台推荐镜像', | |||
myImage: '我的镜像', | |||
myFavImage: '我收藏的镜像', | |||
searchImagePlaceholder: '搜镜像Tag/描述/标签...', | |||
searchImagePlaceholder: '搜镜像Tag/描述/操作系统/安装的软件包/标签...', | |||
useImage: '使用', | |||
submitting: '提交中', | |||
submitFailed: '提交失败', | |||
@@ -53,7 +53,7 @@ export const CreatePageConfigs = { | |||
taskDescr: { required: false, }, | |||
branchName: { required: true, }, | |||
model: { required: false, multiple: true, useExceedSize: true }, | |||
imagev1: { required: true }, | |||
imagev1: { required: true, type: -1 }, | |||
dataset: { required: false, type: 0, useExceedSize: true }, | |||
networkType: { required: true }, | |||
spec: { required: true }, | |||
@@ -99,7 +99,7 @@ export const CreatePageConfigs = { | |||
taskType: {}, | |||
branchName: {}, | |||
model: { required: false, multiple: true, useExceedSize: true }, | |||
imagev1: { required: true, type: 2 }, | |||
imagev1: { required: true, type: -1 }, | |||
dataset: { required: false, type: 0, useExceedSize: true }, | |||
networkType: { required: true }, | |||
spec: {}, | |||
@@ -134,7 +134,7 @@ export const CreatePageConfigs = { | |||
taskDescr: { required: false, }, | |||
branchName: { required: true, }, | |||
model: { required: false, multiple: true, useExceedSize: true }, | |||
imagev2: { required: true, relatedSpec: true }, | |||
imagev1: { required: true, type: -1 }, | |||
dataset: { required: false, useExceedSize: true }, | |||
networkType: { required: true }, | |||
spec: { required: true }, | |||
@@ -154,7 +154,7 @@ export const CreatePageConfigs = { | |||
taskDescr: { required: false, }, | |||
branchName: { required: true, }, | |||
model: { required: false, multiple: true, useExceedSize: true }, | |||
imagev2: { required: true, relatedSpec: true }, | |||
imagev1: { required: true, type: -1 }, | |||
dataset: { required: false, useExceedSize: true }, | |||
networkType: { required: true }, | |||
spec: { required: true }, | |||
@@ -194,7 +194,7 @@ export const CreatePageConfigs = { | |||
taskDescr: { required: false, }, | |||
branchName: { required: true, }, | |||
model: { required: false, multiple: true, useExceedSize: true }, | |||
imagev2: { required: true, relatedSpec: true }, | |||
imagev1: { required: true, type: -1 }, | |||
dataset: { required: false, useExceedSize: true }, | |||
networkType: { required: true }, | |||
spec: { required: true }, | |||
@@ -214,7 +214,7 @@ export const CreatePageConfigs = { | |||
taskDescr: { required: false, }, | |||
branchName: { required: true, }, | |||
model: { required: false, multiple: true, useExceedSize: true }, | |||
imagev2: { required: true, relatedSpec: true }, | |||
imagev1: { required: true, type: -1 }, | |||
dataset: { required: false, useExceedSize: true }, | |||
networkType: { required: true }, | |||
spec: { required: true }, | |||
@@ -244,7 +244,7 @@ export const CreatePageConfigs = { | |||
taskDescr: { required: false, }, | |||
branchName: { required: true, }, | |||
model: { required: false, multiple: true }, | |||
imagev1: { required: true }, | |||
imagev1: { required: true, type: -1 }, | |||
bootFile: { required: true, sampleUrl: 'https://openi.pcl.ac.cn/OpenIOSSG/MNIST_PytorchExample_GPU' }, | |||
dataset: { required: true, type: 0 }, | |||
networkType: { required: true }, | |||
@@ -303,7 +303,7 @@ export const CreatePageConfigs = { | |||
taskType: {}, | |||
branchName: {}, | |||
model: { multiple: true }, | |||
imagev1: { required: true, type: 2 }, | |||
imagev1: { required: true, type: -1 }, | |||
bootFile: { required: true, sampleUrl: 'https://openi.pcl.ac.cn/OpenIOSSG/OpenI_Cloudbrain_Example/src/branch/master/gpu_mnist_example/train.py' }, | |||
dataset: { required: true, type: 0 }, | |||
runParameters: { required: false }, | |||
@@ -351,7 +351,7 @@ export const CreatePageConfigs = { | |||
taskDescr: { required: false, }, | |||
branchName: { required: true, }, | |||
model: { required: false, multiple: true }, | |||
imagev2: { required: true, relatedSpec: true }, | |||
imagev1: { required: true, type: -1 }, | |||
bootFile: { required: true, sampleUrl: 'https://openi.pcl.ac.cn/OpenIOSSG/OpenI_Cloudbrain_Example/src/branch/master/gcu_mnist_example/train.py' }, | |||
dataset: { required: true }, | |||
runParameters: { required: false }, | |||
@@ -375,7 +375,7 @@ export const CreatePageConfigs = { | |||
taskDescr: { required: false, }, | |||
branchName: { required: true, }, | |||
model: { required: false, multiple: true }, | |||
imagev2: { required: true, relatedSpec: true }, | |||
imagev1: { required: true, type: -1 }, | |||
bootFile: { required: true, sampleUrl: '' }, | |||
dataset: { required: true }, | |||
runParameters: { required: false }, | |||
@@ -396,8 +396,8 @@ export const CreatePageConfigs = { | |||
taskName: { required: true, }, | |||
taskDescr: { required: false, }, | |||
branchName: { required: true, }, | |||
model: { required: false, multiple: false }, | |||
imagev2: { required: true, relatedSpec: true }, | |||
model: { required: false, multiple: true }, | |||
imagev1: { required: true, type: -1 }, | |||
bootFile: { required: true, sampleUrl: '' }, | |||
dataset: { required: true }, | |||
runParameters: { required: false }, | |||
@@ -458,7 +458,7 @@ export const CreatePageConfigs = { | |||
taskType: {}, | |||
branchName: {}, | |||
model: { required: true, multiple: false }, | |||
imagev1: { required: true, type: 2 }, | |||
imagev1: { required: true, type: -1 }, | |||
bootFile: { required: true, sampleUrl: 'https://openi.pcl.ac.cn/OpenIOSSG/OpenI_Cloudbrain_Example/src/branch/master/gpu_mnist_example/inference.py' }, | |||
dataset: { required: true, type: 0 }, | |||
runParameters: { required: false }, | |||
@@ -481,7 +481,7 @@ export const CreatePageConfigs = { | |||
taskDescr: { required: false, }, | |||
branchName: { required: true, }, | |||
model: { required: true, multiple: false }, | |||
imagev2: { required: true, relatedSpec: true }, | |||
imagev1: { required: true, type: -1 }, | |||
bootFile: { required: true, sampleUrl: 'https://openi.pcl.ac.cn/OpenIOSSG/OpenI_Cloudbrain_Example/src/branch/master/gpgpu_mnist_example/inference.py' }, | |||
dataset: { required: true, type: 0 }, | |||
runParameters: { required: false }, | |||
@@ -511,7 +511,7 @@ export const CreatePageConfigs = { | |||
branchName: { required: true, }, | |||
model: { required: false, }, | |||
algBechmarkType: { required: true, }, | |||
imagev1: { required: true, }, | |||
imagev1: { required: true, type: -1 }, | |||
networkType: { required: true }, | |||
spec: { required: true, }, | |||
@@ -581,7 +581,7 @@ export const CreatePageConfigs = { | |||
branchName: {}, | |||
bootFile: { required: true, sampleUrl: 'https://openi.pcl.ac.cn/OpenIOSSG/Online-Inference_Example' }, | |||
model: { required: false, multiple: true }, | |||
imagev1: { required: true, type: 2 }, | |||
imagev1: { required: true, type: -1 }, | |||
dataset: { required: false, type: 0, useExceedSize: true }, | |||
networkType: { required: true }, | |||
spec: {}, | |||
@@ -1266,7 +1266,7 @@ export const DetailPageConfigs = { | |||
branchName: { required: true, }, | |||
model: { required: false, }, | |||
algBechmarkType: { required: true, }, | |||
imagev1: { required: true, }, | |||
imagev1: { required: true, type: -1 }, | |||
networkType: { required: true }, | |||
spec: { required: true, }, | |||
@@ -44,9 +44,9 @@ | |||
<div class="line"></div> | |||
<div class="form-body-content"> | |||
<div class="main-title params-setting">{{ $t('cloudbrainObj.paramsSetting') }}:</div> | |||
<ImageSelectV1 ref="imagev1Ref" v-if="formCfg.imagev1" v-model="state.image_url" | |||
:required="formCfg.imagev1.required" | |||
:type="formCfg.imagev1.type != undefined ? formCfg.imagev1.type : 0"> | |||
<ImageSelectV1 ref="imagev1Ref" v-if="formCfg.imagev1" v-model="state.image_url" :configs="pageCfg" | |||
:spec="state.spec" :required="formCfg.imagev1.required" | |||
:type="formCfg.imagev1.type != undefined ? formCfg.imagev1.type : 0" @changeImage="changeImage"> | |||
</ImageSelectV1> | |||
<ImageSelectV2 ref="imagev2Ref" v-if="formCfg.imagev2" v-model="state.image" :images="imageList" | |||
:configs="pageCfg" :spec="state.spec" :networkType="state.networkType" @changeImages="changeImages" | |||
@@ -443,6 +443,15 @@ export default { | |||
console.log(err); | |||
}); | |||
}, | |||
changeImage() { | |||
if (this.isModifyTask && this.modeifyTaskId && this.oldTask.image_url && this.state.spec == this.oldTask.spec.id | |||
&& this.state.image_url == this.oldTask.image_url | |||
) { | |||
return; | |||
} else { | |||
this.state.image_url = ''; | |||
} | |||
}, | |||
changeImages(images) { | |||
this.imageList = images || []; | |||
let image = this.imageList[0]; | |||
@@ -98,7 +98,7 @@ export class CloudBrainTools { | |||
} else { | |||
task.canDelete = false; | |||
} | |||
if (task.compute_source == 'GPU' && task.job_type == 'DEBUG') { | |||
if ((task.compute_source == 'GPU' || task.compute_source == 'GCU' || task.compute_source == 'MLU'|| task.compute_source == 'ILUVATAR-GPGPU'|| task.compute_source == 'METAX-GPGPU') && task.job_type == 'DEBUG') { | |||
task.hasDebugMore = true; | |||
if (task.canDebug) { | |||
task.canSaveImage = true; | |||
@@ -0,0 +1,162 @@ | |||
<template> | |||
<div class="condition-wrap"> | |||
<div> | |||
<div class="tab-c"> | |||
<div class="tab-item" v-for="(item) in tabList" :class="conds.tab == item.key ? 'focus' : ''" :key="item.key" | |||
@click="changeTab(item)"> | |||
{{ item.label }} | |||
</div> | |||
</div> | |||
</div> | |||
<div class="condition-b"> | |||
<div class="only-recommend-c"></div> | |||
<div> | |||
<el-dropdown class="sort-c" trigger="click" size="default"> | |||
<span class="el-dropdown-link"> | |||
{{ $t('datasets.sort') }}<i class="el-icon-caret-bottom el-icon--right"></i> | |||
</span> | |||
<el-dropdown-menu slot="dropdown"> | |||
<el-dropdown-item :class="conds.sort == item.key ? 'active' : ''" v-for="item in sortList" :key="item.key" | |||
@click.native="changeSort(item)"> | |||
{{ item.label }} | |||
</el-dropdown-item> | |||
</el-dropdown-menu> | |||
</el-dropdown> | |||
</div> | |||
</div> | |||
</div> | |||
</template> | |||
<script> | |||
import { i18n } from '~/langs'; | |||
const SortList = [{ | |||
key: '', | |||
label: i18n.t('datasets.default'), | |||
}, { | |||
key: 'moststars', | |||
label: i18n.t('datasets.moststars'), | |||
}, { | |||
key: 'mostused', | |||
label: i18n.t('datasets.mostusecount'), | |||
}, { | |||
key: 'newest', | |||
label: i18n.t('datasets.newest'), | |||
}]; | |||
export default { | |||
name: "Condition", | |||
props: { | |||
condition: { type: Object, default: () => ({}) }, | |||
}, | |||
components: {}, | |||
data() { | |||
return { | |||
isLogin: false, | |||
tabList: [{ | |||
key: '0', | |||
label: this.$t('imagesObj.image_public'), | |||
}, { | |||
key: '1', | |||
label: this.$t('imagesObj.image_my'), | |||
}, { | |||
key: '2', | |||
label: this.$t('imagesObj.image_collected'), | |||
}], | |||
sortList: [], | |||
conds: { | |||
tab: '0', | |||
sort: '', | |||
}, | |||
}; | |||
}, | |||
methods: { | |||
changeTab(item) { | |||
this.conds.tab = item.key; | |||
if (item.key == '1') { | |||
this.conds.sort = 'newest'; | |||
this.sortList = SortList.slice(1); | |||
} else { | |||
this.conds.sort = ''; | |||
this.sortList = SortList.slice(0); | |||
} | |||
this.$emit('changeCondition', { | |||
tab: item.key, | |||
sort: this.conds.sort, | |||
}); | |||
}, | |||
changeSort(item) { | |||
this.conds.sort = item.key; | |||
this.$emit('changeCondition', { | |||
sort: this.conds.sort, | |||
}); | |||
} | |||
}, | |||
watch: { | |||
condition: { | |||
handler(newVal) { | |||
this.conds.tab = newVal.tab || '0'; | |||
this.conds.sort = newVal.sort || ''; | |||
this.sortList = SortList.slice(newVal.tab == '1' ? 1 : 0); | |||
}, | |||
immediate: true, | |||
deep: true, | |||
}, | |||
}, | |||
beforeMount() { | |||
this.isLogin = !!document.querySelector('meta[name="_uid"]'); | |||
if (!this.isLogin) { | |||
this.tabList.splice(1, Infinity); | |||
} | |||
}, | |||
mounted() { }, | |||
}; | |||
</script> | |||
<style scoped lang="less"> | |||
.condition-wrap { | |||
margin: 10px 0 2px; | |||
.tab-c { | |||
display: flex; | |||
align-items: center; | |||
.tab-item { | |||
margin-right: 32px; | |||
padding: 4px 0; | |||
text-align: center; | |||
font-size: 14px; | |||
color: rgb(65, 80, 88); | |||
cursor: pointer; | |||
&.focus { | |||
font-weight: bold; | |||
color: #3291f8; | |||
font-weight: bold; | |||
border-bottom: 2px solid; | |||
} | |||
} | |||
} | |||
.condition-b { | |||
display: flex; | |||
align-items: center; | |||
justify-content: space-between; | |||
margin-bottom: 8px; | |||
.only-recommend-c { | |||
margin-right: 22px; | |||
} | |||
.sort-c { | |||
color: rgba(0, 0, 0, 0.87); | |||
cursor: pointer; | |||
} | |||
} | |||
} | |||
/deep/.el-dropdown-menu__item.active { | |||
color: #409EFF; | |||
background-color: rgba(179, 216, 255, 0.3); | |||
} | |||
</style> |
@@ -0,0 +1,289 @@ | |||
<template> | |||
<div> | |||
<div class="top-title">{{ $t('imagesObj.cloudbrain_images') }}</div> | |||
<div class="filter-main" v-show="!showSecond"> | |||
<div class="filter-c" v-for="(item, index) in mainData" :key="index" | |||
v-show="item.key != 'framework_version' || item.data.length > 0"> | |||
<div class="filter-title">{{ item.title }}</div> | |||
<div class="filter-item-c"> | |||
<div class="filter-item" v-for="(_item) in item.showData" @click="changeFilter(item, _item)" :key="_item.k" | |||
:style="conds[item.key] == _item.k ? | |||
{ backgroundColor: _item.focusBgColor || item.focusBgColor, color: _item.focusColor || item.focusColor } | |||
: { backgroundColor: _item.bgColor || item.bgColor, color: _item.color || item.color }"> | |||
{{ _item.v }} | |||
</div> | |||
</div> | |||
<div class="filter-view-more-c" v-if="item.data.length > item.showMaxLen"> | |||
<span class="filter-view-more" @click="goMore(item)"> | |||
<i class="el-icon-arrow-down"></i><span>{{ $t('expandMore') }}</span> | |||
</span> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="filter-second" v-show="showSecond"> | |||
<div class="filter-second-hd"> | |||
<span class="filter-second-go-back" @click="goBack()"> | |||
<i class="el-icon-back"></i><span>{{ $t('goBack') }}</span> | |||
</span> | |||
</div> | |||
<div class="filter-title">{{ secondData.title }}</div> | |||
<div class="filter-search"> | |||
<el-input :placeholder="$t('repos.search')" prefix-icon="el-icon-search" v-model="searchKeyword" clearable | |||
@input="searchFilterItem"> | |||
</el-input> | |||
</div> | |||
<div class="filter-item-c"> | |||
<div class="filter-item" v-for="(_item) in secondData.secondShowData" :key="_item.k" | |||
@click="changeFilter(secondData, _item)" :style="conds[secondData.key] == _item.k ? | |||
{ backgroundColor: _item.focusBgColor || item.focusBgColor, color: _item.focusColor || item.focusColor } | |||
: { backgroundColor: _item.bgColor || item.bgColor, color: _item.color || item.color }"> | |||
{{ _item.v }} | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</template> | |||
<script> | |||
import { getStaticFile } from '~/apis/modules/common'; | |||
import { COMPUTER_RESOURCES_COLORS } from '~/const'; | |||
export default { | |||
name: "Filters", | |||
props: { | |||
condition: { type: Object, default: () => ({}) }, | |||
}, | |||
components: {}, | |||
data() { | |||
return { | |||
mainData: [{ | |||
title: this.$t('cloudbrainObj.computeResource'), | |||
key: 'compute_resource', | |||
bgColor: 'rgb(248, 249, 250)', | |||
color: 'rgb(65, 80, 88)', | |||
focusBgColor: 'rgb(3, 102, 214)', | |||
focusColor: 'rgb(255, 255, 255)', | |||
data: [], | |||
showData: [], | |||
showMaxLen: 10, | |||
}, { | |||
title: this.$t('imagesObj.framework'), | |||
key: 'framework', | |||
bgColor: 'rgb(248, 249, 250)', | |||
color: 'rgb(65, 80, 88)', | |||
focusBgColor: 'rgb(3, 102, 214)', | |||
focusColor: 'rgb(255, 255, 255)', | |||
data: [], | |||
showData: [], | |||
showMaxLen: 10, | |||
}, { | |||
title: this.$t('imagesObj.frameworkVersion'), | |||
key: 'framework_version', | |||
bgColor: 'rgb(248, 249, 250)', | |||
color: 'rgb(65, 80, 88)', | |||
focusBgColor: 'rgb(3, 102, 214)', | |||
focusColor: 'rgb(255, 255, 255)', | |||
data: [], | |||
showData: [], | |||
showMaxLen: 20, | |||
}, { | |||
title: this.$t('imagesObj.pyVersion'), | |||
key: 'python', | |||
bgColor: 'rgb(248, 249, 250)', | |||
color: 'rgb(65, 80, 88)', | |||
focusBgColor: 'rgb(3, 102, 214)', | |||
focusColor: 'rgb(255, 255, 255)', | |||
data: [], | |||
showData: [], | |||
showMaxLen: 20, | |||
}, { | |||
title: this.$t('imagesObj.cudaVersion'), | |||
key: 'cuda', | |||
bgColor: 'rgb(248, 249, 250)', | |||
color: 'rgb(65, 80, 88)', | |||
focusBgColor: 'rgb(3, 102, 214)', | |||
focusColor: 'rgb(255, 255, 255)', | |||
data: [], | |||
showData: [], | |||
showMaxLen: 20, | |||
}], | |||
filterData: {}, | |||
conds: { | |||
compute_resource: '', | |||
framework: '', | |||
framework_version: '', | |||
python: '', | |||
cuda: '', | |||
}, | |||
showSecond: false, | |||
secondData: {}, | |||
searchKeyword: '', | |||
}; | |||
}, | |||
methods: { | |||
goMore(item) { | |||
this.secondData = item; | |||
this.searchKeyword = ''; | |||
this.secondData.secondShowData = item.data; | |||
this.showSecond = true; | |||
}, | |||
goBack() { | |||
this.showSecond = false; | |||
}, | |||
changeFilter(item, _item) { | |||
const value = this.conds[item.key] == _item.k ? '' : _item.k; | |||
const changes = { | |||
[item.key]: value, | |||
}; | |||
if (item.key == 'framework') { | |||
const frameworkVersionObj = this.mainData.find(itm => itm.key == 'framework_version'); | |||
changes['framework_version'] = ''; | |||
frameworkVersionObj.data = value ? ((this.filterData['framework_version'] || {})[value] || []).map(item => ({ k: item, v: item })) : []; | |||
frameworkVersionObj.showData = frameworkVersionObj.data.slice(0, frameworkVersionObj.showMaxLen); | |||
} | |||
this.$emit('changeCondition', changes); | |||
}, | |||
searchFilterItem() { | |||
const keyword = this.searchKeyword.trim().toLocaleLowerCase(); | |||
this.secondData.secondShowData = this.secondData.data.filter(item => { | |||
return item.v.toString().toLocaleLowerCase().indexOf(keyword) >= 0; | |||
}); | |||
}, | |||
}, | |||
watch: { | |||
condition: { | |||
handler(newVal) { | |||
this.conds.compute_resource = newVal.compute_resource || ''; | |||
this.conds.framework = newVal.framework || ''; | |||
this.conds.framework_version = newVal.framework_version || ''; | |||
const frameworkVersionObj = this.mainData.find(itm => itm.key == 'framework_version'); | |||
frameworkVersionObj.data = this.conds.framework ? ((this.filterData['framework_version'] || {})[this.conds.framework] || []).map(item => ({ k: item, v: item })) : []; | |||
frameworkVersionObj.showData = frameworkVersionObj.data.slice(0, frameworkVersionObj.showMaxLen); | |||
this.conds.python = newVal.python || ''; | |||
this.conds.cuda = newVal.cuda || ''; | |||
}, | |||
immediate: true, | |||
deep: true, | |||
}, | |||
}, | |||
beforeMount() { | |||
getStaticFile('/images_version.json').then(res => { | |||
const data = res.data; | |||
if (data) { | |||
this.filterData = data; | |||
for (let i = 0, iLen = this.mainData.length; i < iLen; i++) { | |||
const filterItem = this.mainData[i]; | |||
const key = filterItem.key; | |||
const max = filterItem.showMaxLen; | |||
if (data[key] && key != 'framework_version') { | |||
if (key == 'compute_resource') { | |||
filterItem.data = data[key].map(item => ({ | |||
k: item, | |||
v: this.$t('computeResourceTitle.' + item) || item, | |||
focusBgColor: COMPUTER_RESOURCES_COLORS[item], | |||
})); | |||
} else { | |||
filterItem.data = data[key].map(item => ({ k: item, v: item })); | |||
} | |||
if (filterItem.sortOr) { | |||
filterItem.data = filterItem.data.sort((a, b) => a.v.localeCompare(b.v)); | |||
} | |||
filterItem.showData = filterItem.data.slice(0, max); | |||
} | |||
} | |||
} | |||
}).catch(err => { | |||
console.log(err); | |||
}); | |||
}, | |||
mounted() { }, | |||
}; | |||
</script> | |||
<style scoped lang="less"> | |||
.top-title { | |||
font-size: 24px; | |||
color: #101010; | |||
height: 40px; | |||
line-height: 40px; | |||
margin: 10px 0 20px; | |||
} | |||
.filter-c { | |||
margin-bottom: 32px; | |||
.filter-title { | |||
font-size: 18px; | |||
color: rgba(50, 145, 248, 1); | |||
margin: 14px 0; | |||
} | |||
.filter-item-c { | |||
display: flex; | |||
flex-wrap: wrap; | |||
.filter-item { | |||
border-radius: 3px; | |||
padding: 3px 10px; | |||
margin-right: 10px; | |||
margin-bottom: 10px; | |||
cursor: pointer; | |||
} | |||
} | |||
.filter-view-more-c { | |||
margin-top: 6px; | |||
.filter-view-more { | |||
color: rgb(50, 145, 248); | |||
font-size: 14px; | |||
cursor: pointer; | |||
i { | |||
margin-right: 4px; | |||
} | |||
} | |||
} | |||
} | |||
.filter-second { | |||
.filter-second-hd { | |||
margin: 14px 0 24px 0; | |||
.filter-second-go-back { | |||
color: rgb(50, 145, 248); | |||
font-size: 14px; | |||
cursor: pointer; | |||
i { | |||
margin-right: 4px; | |||
} | |||
} | |||
} | |||
.filter-title { | |||
font-size: 18px; | |||
color: rgba(50, 145, 248, 1); | |||
margin: 14px 0; | |||
} | |||
.filter-search { | |||
margin: 5px 10px 10px 0; | |||
} | |||
.filter-item-c { | |||
display: flex; | |||
flex-wrap: wrap; | |||
max-height: 605px; | |||
overflow-y: auto; | |||
.filter-item { | |||
border-radius: 3px; | |||
padding: 3px 10px; | |||
margin-right: 10px; | |||
margin-bottom: 10px; | |||
cursor: pointer; | |||
} | |||
} | |||
} | |||
</style> |
@@ -0,0 +1,487 @@ | |||
<template> | |||
<div class="item"> | |||
<div class="item-top"> | |||
<div class="title-c"> | |||
<div class="title"> | |||
<span> | |||
<span :title="data.tag">{{ data.tag }}</span> | |||
</span> | |||
<img v-show="data.type == 5" src="/img/jian.svg" style="margin-left:4px"> | |||
</div> | |||
<div class="fav-c" :class="condition.tab == 1 ? 'fav-disabled' : ''" @click.prevent.stop="changeFav(data)"> | |||
<i v-if="!isStar" class="heart outline icon" :title="$t('star')"></i> | |||
<i v-if="isStar" class="heart icon" :title="$t('unStar')"></i> | |||
<span>{{ numStars }}</span> | |||
</div> | |||
</div> | |||
<div class="labels"> | |||
<a class="label label-compute-resource" | |||
:style="data.computeResourceColor ? `background-color: ${data.computeResourceColor};` : ''">{{ | |||
data.computeResourceShow }}</a> | |||
<a v-for="(item, index) in data.topics" :key="index" class="label">{{ item }}</a> | |||
</div> | |||
<div class="content-row"> | |||
<div class="content-row-item half"> | |||
<div>{{ $t('imagesObj.framework') }}:</div> | |||
<div>{{ data.framework }} {{ data.frameworkVersion }}</div> | |||
</div> | |||
<div class="content-row-item half"> | |||
<div>{{ $t('imagesObj.pyVersion') }}:</div> | |||
<div v-show="data.pythonVersion">Python {{ data.pythonVersion }}</div> | |||
</div> | |||
</div> | |||
<div class="content-row"> | |||
<div class="content-row-item half"> | |||
<div>{{ $t('imagesObj.cudaVersion') }}:</div> | |||
<div v-if="data.compute_resource != 'GPU'">--</div> | |||
<div v-else> | |||
<span v-show="data.cudaVersion">Cuda {{ data.cudaVersion }}</span> | |||
</div> | |||
</div> | |||
<div class="content-row-item half"> | |||
<div>{{ $t('imagesObj.operationSystem') }}:</div> | |||
<div>{{ data.operationSystem }} {{ data.operationSystemVersion }}</div> | |||
</div> | |||
</div> | |||
<div class="content-row"> | |||
<div class="content-row-item"> | |||
<div>{{ $t('imagesObj.pyPackge') }}:</div> | |||
<div>{{ data.thirdPackagesShow }}</div> | |||
</div> | |||
</div> | |||
<div class="content-row"> | |||
<div class="content-row-item"> | |||
<div>{{ $t('imagesObj.descr') }}:</div> | |||
<div class="descr" :title="data.description"> {{ data.description }} </div> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="footer"> | |||
<div class="footer-l"> | |||
<a v-if="data.userName" :href="`/${data.userName}`" class="avatar-c" :title="data.userName"> | |||
<img class="avatar" :src="data.relAvatarLink"> | |||
</a> | |||
<a v-else href="javascript:;" class="avatar-c"> | |||
<img class="avatar" src="/user/avatar/Ghost/-1"> | |||
</a> | |||
<span style="margin-right:10px;" :title="$t('modelManage.createTime')"> {{ data.createTimeStr }} </span> | |||
<span style="margin-right:10px;" :title="$t('datasets.citations')"> | |||
<i class="el-icon-link"></i> | |||
<span style="color:rgba(16, 16, 16, 0.9);">{{ data.useCount }}</span> | |||
</span> | |||
<span class="status" style="margin-right:10px;" v-if="condition.tab == 1"> | |||
<el-tooltip v-if="data.status == 0" effect="dark" :content="$t('imagesObj.imageCommitting')" placement="top"> | |||
<i class="CREATING" style="margin-right:3px"></i> | |||
</el-tooltip> | |||
<el-tooltip v-if="data.status == 1" effect="dark" :content="$t('imagesObj.imageCommitSuccess')" placement="top"> | |||
<i class="SUCCEEDED" style="margin-right:3px"></i> | |||
</el-tooltip> | |||
<el-tooltip v-if="data.status == 2" effect="dark" :content="$t('imagesObj.imageCommitErrorTips')" | |||
placement="top"> | |||
<i class="FAILED" style="margin-right:3px"></i> | |||
</el-tooltip> | |||
<span v-if="data.status === 0">{{ $t('imagesObj.committing') }}</span> | |||
<span v-if="data.status === 1">{{ $t('imagesObj.commitSuccess') }}</span> | |||
<span v-if="data.status === 2">{{ $t('imagesObj.commitFailed') }}</span> | |||
</span> | |||
<span class="apply-status"> | |||
<div v-if="data.status === 1"> | |||
<div v-if="data.apply_status === 2" style="display: flex;align-items:center;justify-content:center;"> | |||
<el-tooltip effect="dark" :content="$t('imagesObj.recommendNeedReview')" placement="top"> | |||
<i class="CLOCK" style="margin-right:3px"></i> | |||
</el-tooltip> | |||
<span style="color: rgb(250, 140, 22);">{{ $t('imagesObj.recommendNeedReview') }}</span> | |||
</div> | |||
<div v-if="data.apply_status === 3" style="display: flex;align-items:center;justify-content:center;"> | |||
<el-tooltip effect="dark" :content="$t('imagesObj.recommendReviewApproved')" placement="top"> | |||
<i class="SUCCEEDED" style="margin-right:3px"></i> | |||
</el-tooltip> | |||
<span style="color: rgb(19, 194, 141);">{{ $t('imagesObj.recommendReviewApproved') }}</span> | |||
</div> | |||
<div v-if="data.apply_status === 4" style="display: flex;align-items:center;justify-content:center;"> | |||
<el-tooltip effect="dark" :content="data.message" placement="top"> | |||
<i class="FAILED" style="margin-right:3px"></i> | |||
</el-tooltip> | |||
<span style="color: red">{{ $t('imagesObj.recommendReviewFailed') }}</span> | |||
</div> | |||
</div> | |||
</span> | |||
</div> | |||
<div class="footer-r" v-if="data.status != 0"> | |||
<a class="btn-op" href="javascript:void(0);" v-if="data.place" @click="copy(data)"> | |||
<i class="el-icon-document-copy"></i> | |||
<span>{{ $t('imagesObj.copyAdress') }}</span> | |||
</a> | |||
<a v-if="condition.tab == 1 && (data.apply_status == 0 || data.apply_status == 1 || data.apply_status === 4) && data.type != 5" | |||
class="btn-op" href="javascript:void(0);" @click="apply(data)"> | |||
<i class="ri-rocket-2-line" style="margin-right:0;"></i> | |||
<span>{{ $t('imagesObj.applyForRecommend') }}</span> | |||
</a> | |||
<a v-if="condition.tab == 1" class="btn-op" href="javascript:void(0);" @click="edit(data)"> | |||
<i class="el-icon-edit-outline"></i> | |||
<span>{{ $t('modelManage.edit') }}</span> | |||
</a> | |||
<a v-if="condition.tab == 1" class="btn-op delete" href="javascript:void(0);" @click="deleteImage(data)"> | |||
<i class="el-icon-delete"></i> | |||
<span>{{ $t('cloudbrainObj.delete') }}</span> | |||
</a> | |||
</div> | |||
</div> | |||
</div> | |||
</template> | |||
<script> | |||
import { putImageAction, deleteImage, getImageById } from '~/apis/modules/images'; | |||
export default { | |||
name: "Item", | |||
props: { | |||
condition: { type: Object, default: () => ({}) }, | |||
data: { type: Object, default: () => ({}) }, | |||
}, | |||
components: {}, | |||
data() { | |||
return { | |||
isStar: false, | |||
numStars: 0, | |||
isSetting: false, | |||
hasOnlineUrl: 0, | |||
refreshTimer: null, | |||
}; | |||
}, | |||
watch: { | |||
data: { | |||
handler(newVal) { | |||
this.isStar = newVal.isStar; | |||
this.numStars = newVal.numStars; | |||
this.refreshStatus(); | |||
}, | |||
immediate: true, | |||
deep: true, | |||
}, | |||
}, | |||
methods: { | |||
changeFav(item) { | |||
if (this.condition.tab == 1) return; | |||
if (this.isSetting) return; | |||
this.isSetting = true; | |||
putImageAction({ | |||
id: item.id, | |||
action: this.isStar ? 'unstar' : 'star', | |||
}).then(res => { | |||
this.isSetting = false; | |||
if (res.data.Code == '0') { | |||
this.isStar = !this.isStar; | |||
this.numStars = this.numStars + (this.isStar ? 1 : -1); | |||
this.$message.success(this.isStar ? this.$t('datasets.starSuccess') : this.$t('datasets.unstarSuccess')); | |||
this.$emit('changeImage'); | |||
} else if (res.data.code == '401') { | |||
window.location.href = `/user/login?redirect_to=${encodeURIComponent(window.location.href)}`; | |||
} else { | |||
this.$message.error(res.data.msg); | |||
} | |||
}).catch(err => { | |||
console.log(err); | |||
this.isSetting = false; | |||
if (err.request.responseURL.indexOf('/user/login') >= 0) { | |||
window.location.href = `/user/login?redirect_to=${encodeURIComponent(window.location.href)}`; | |||
} else { | |||
this.$message.error(err); | |||
} | |||
}); | |||
}, | |||
copy(item) { | |||
const tInput = document.createElement("input"); | |||
tInput.value = item.place; | |||
document.body.appendChild(tInput); | |||
tInput.select(); | |||
document.execCommand("Copy"); | |||
tInput.remove(); | |||
this.$message({ | |||
type: 'success', | |||
message: this.$t('copySuccess'), | |||
}); | |||
}, | |||
refreshStatus() { | |||
this.refreshTimer && clearInterval(this.refreshTimer); | |||
this.refreshTimer = setInterval(() => { | |||
if (this.data.status != 0) { | |||
this.refreshTimer && clearInterval(this.refreshTimer); | |||
return; | |||
} | |||
getImageById({ id: this.data.id }).then(res => { | |||
res = res.data; | |||
if (res.id == this.data.id) { | |||
const updateData = { ...res }; | |||
delete updateData['userName']; | |||
delete updateData['relAvatarLink']; | |||
this.$emit('refreshImage', updateData); | |||
} | |||
}).catch(err => { | |||
console.log(err); | |||
}); | |||
}, 5 * 1000); | |||
}, | |||
deleteImage(item) { | |||
if (this.condition.tab != 1) return; | |||
if (this.isSetting) return; | |||
this.$confirm(this.$t('imagesObj.deleteTips'), this.$t('tips'), { | |||
confirmButtonText: this.$t('confirm1'), | |||
cancelButtonText: this.$t('cancel'), | |||
type: 'warning', | |||
lockScroll: false, | |||
}).then(() => { | |||
this.isSetting = true; | |||
deleteImage({ id: item.id }).then(res => { | |||
this.isSetting = false; | |||
res = res.data; | |||
if (res.Code == '0') { | |||
this.$message({ | |||
type: 'success', | |||
message: this.$t('imagesObj.deleteSuccessTips'), | |||
}); | |||
this.$emit('changeImage'); | |||
} else { | |||
this.$message({ | |||
type: 'error', | |||
message: res.Message, | |||
}); | |||
} | |||
}).catch(err => { | |||
this.isSetting = false; | |||
console.log(err); | |||
this.$message({ | |||
type: 'error', | |||
message: this.$t('operationFailed'), | |||
}); | |||
}); | |||
}).catch(() => { }); | |||
}, | |||
apply(item) { | |||
location.href = `/image/${item.id}/apply`; | |||
}, | |||
edit(item) { | |||
location.href = `/image/${item.id}/imageSquare`; | |||
} | |||
}, | |||
beforeMount() { | |||
this.isStar = this.data.isStar; | |||
this.numStars = this.data.numStars; | |||
}, | |||
mounted() { | |||
this.data.status == 0 && this.refreshStatus(); | |||
}, | |||
beforeDestroy() { | |||
this.refreshTimer && clearInterval(this.refreshTimer); | |||
} | |||
}; | |||
</script> | |||
<style scoped lang="less"> | |||
.item { | |||
border-color: rgb(232, 232, 232); | |||
border-width: 1px; | |||
border-style: solid; | |||
border-radius: 5px; | |||
box-shadow: rgba(232, 232, 232, 0.6) 0px 4px 4px 0px; | |||
overflow: hidden; | |||
padding: 15px; | |||
background: transparent; | |||
display: flex; | |||
justify-content: space-between; | |||
flex-direction: column; | |||
height: 100%; | |||
&:hover { | |||
border-color: rgba(204, 204, 255, 0.6); | |||
box-shadow: rgba(204, 204, 255, 0.6) 0px 4px 8px 0px; | |||
background: url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20version%3D%221.1%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%221%22%20x1%3D%220%22%20x2%3D%221%22%20y1%3D%220%22%20y2%3D%220%22%20gradientTransform%3D%22matrix(-0.34000000000000014%2C%20-0.643%2C%200.07087403200000002%2C%20-0.34000000000000014%2C%200.935%2C%200.997)%22%3E%3Cstop%20stop-color%3D%22%23ccfff4%22%20stop-opacity%3D%220.6%22%20offset%3D%220.01%22%3E%3C%2Fstop%3E%3Cstop%20stop-color%3D%22%23ece2ff%22%20stop-opacity%3D%220%22%20offset%3D%221%22%3E%3C%2Fstop%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Crect%20width%3D%22100%25%22%20height%3D%22100%25%22%20fill%3D%22url(%231)%22%3E%3C%2Frect%3E%3C%2Fsvg%3E"); | |||
.title span { | |||
color: rgba(125, 3, 214, 1) | |||
} | |||
} | |||
} | |||
.title-c { | |||
display: flex; | |||
align-items: center; | |||
.title { | |||
flex: 1; | |||
overflow: hidden; | |||
text-overflow: ellipsis; | |||
white-space: nowrap; | |||
display: flex; | |||
align-items: center; | |||
color: rgb(3, 102, 214); | |||
a { | |||
max-width: calc(100% - 40px); | |||
overflow: hidden; | |||
text-overflow: ellipsis; | |||
span { | |||
font-weight: 500; | |||
font-size: 16px; | |||
color: rgb(3, 102, 214); | |||
} | |||
} | |||
} | |||
} | |||
.fav-c { | |||
display: flex; | |||
font-size: 12px; | |||
i { | |||
color: rgb(250, 140, 22); | |||
cursor: pointer; | |||
} | |||
span { | |||
color: rgb(16, 16, 16); | |||
} | |||
&.fav-disabled { | |||
i { | |||
cursor: default; | |||
} | |||
} | |||
} | |||
.content-row { | |||
display: flex; | |||
align-items: center; | |||
font-size: 12px; | |||
color: rgb(136, 136, 136); | |||
margin-top: 4px; | |||
.content-row-item { | |||
display: flex; | |||
min-width: 100%; | |||
&.half { | |||
min-width: 50%; | |||
} | |||
div:nth-child(1) { | |||
width: 90px; | |||
text-align: right; | |||
} | |||
div:nth-child(2) { | |||
flex: 1; | |||
width: 0; | |||
color: rgb(16, 16, 16) | |||
} | |||
} | |||
} | |||
.descr { | |||
font-size: 12px; | |||
font-weight: 300; | |||
color: rgb(136, 136, 136); | |||
text-overflow: ellipsis; | |||
word-break: break-all; | |||
display: -webkit-box; | |||
-webkit-box-orient: vertical; | |||
-webkit-line-clamp: 2; | |||
max-height: 41px; | |||
overflow: hidden; | |||
} | |||
.labels { | |||
overflow: hidden; | |||
text-overflow: ellipsis; | |||
white-space: nowrap; | |||
margin-top: 8px; | |||
.label { | |||
color: rgba(16, 16, 16, 0.8); | |||
border-radius: 4px; | |||
font-size: 12px; | |||
background: rgba(232, 232, 232, 0.6); | |||
padding: 2px 6px; | |||
margin-right: 8px; | |||
cursor: default; | |||
} | |||
.label-compute-resource { | |||
color: white; | |||
} | |||
} | |||
.footer { | |||
margin-top: 12px; | |||
display: flex; | |||
align-items: center; | |||
justify-content: space-between; | |||
height: 20px; | |||
font-size: 12px; | |||
.footer-l { | |||
font-size: 12px; | |||
font-weight: 400; | |||
overflow: hidden; | |||
text-overflow: ellipsis; | |||
white-space: nowrap; | |||
color: rgba(136, 136, 136, 1); | |||
display: flex; | |||
align-items: center; | |||
.avatar-c { | |||
margin-right: 4px; | |||
display: inline-block; | |||
height: 24px; | |||
.avatar { | |||
display: inline-block; | |||
width: 24px; | |||
height: 24px; | |||
border-radius: 100%; | |||
} | |||
} | |||
.status { | |||
display: flex; | |||
align-items: center; | |||
} | |||
.apply-status { | |||
display: flex; | |||
align-items: center; | |||
} | |||
} | |||
.footer-r { | |||
display: flex; | |||
justify-content: end; | |||
font-size: 12px; | |||
font-weight: 300; | |||
color: rgb(136, 136, 136); | |||
.btn-op { | |||
margin-left: 12px; | |||
display: flex; | |||
align-items: center; | |||
i { | |||
margin-right: 2px; | |||
} | |||
&.delete { | |||
color: rgb(255, 37, 37); | |||
} | |||
} | |||
} | |||
} | |||
:lang(en-US) .content-row { | |||
.content-row-item { | |||
div:nth-child(1) { | |||
width: 112px; | |||
} | |||
} | |||
} | |||
</style> |
@@ -0,0 +1,178 @@ | |||
<template> | |||
<div class="list-container"> | |||
<div class="list-item-container" v-loading="loading"> | |||
<div class="item-container" v-for="(item) in list" :key="item.ID"> | |||
<ImageItem :data="item" :condition="condition" @changeImage="changeImage" @refreshImage="refreshImage"> | |||
</ImageItem> | |||
</div> | |||
<div v-show="(!list.length && !loading)" class="no-data"> | |||
<div class="item-empty"> | |||
<div class="item-empty-icon"></div> | |||
<div class="item-empty-tips">{{ $t('modelObj.model_square_empty') }}</div> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="center" v-show="list.length"> | |||
<el-pagination ref="paginationRef" background @current-change="currentChange" @size-change="sizeChange" | |||
:current-page.sync="iPage" :page-sizes="iPageSizes" :page-size.sync="iPageSize" | |||
layout="total, sizes, prev, pager, next, jumper" :total="total"> | |||
</el-pagination> | |||
</div> | |||
</div> | |||
</template> | |||
<script> | |||
import ImageItem from './Item.vue'; | |||
import { getImages } from '~/apis/modules/images'; | |||
import { formatDate } from 'element-ui/lib/utils/date-util'; | |||
import { COMPUTER_RESOURCES_COLORS } from '~/const'; | |||
export default { | |||
name: "List", | |||
props: { | |||
condition: { type: Object, default: () => ({}) }, | |||
}, | |||
components: { ImageItem }, | |||
data() { | |||
return { | |||
loading: false, | |||
list: [], | |||
iPageSizes: [15], | |||
iPageSize: 15, | |||
iPage: 1, | |||
total: 0, | |||
}; | |||
}, | |||
methods: { | |||
getListData() { | |||
this.loading = true; | |||
const params = { | |||
q: this.condition.q, | |||
type: this.condition.tab, | |||
sort: this.condition.sort, | |||
computeResource: this.condition.compute_resource, | |||
framework: this.condition.framework, | |||
frameworkVersion: this.condition.framework_version, | |||
python: this.condition.python, | |||
cuda: this.condition.cuda, | |||
page: this.condition.page, | |||
pageSize: this.condition.pageSize, | |||
}; | |||
getImages(params).then(res => { | |||
res = res.data; | |||
this.loading = false; | |||
this.total = res.count || 0; | |||
this.list = (res.images || []).map(item => { | |||
const thirdPackagesList = []; | |||
const thirdPackages = item.thirdPackages.split('\n'); | |||
thirdPackages.forEach(pkgLine => { | |||
if (pkgLine) { | |||
thirdPackagesList.push(pkgLine.trim().replace('==', ' ')); | |||
} | |||
}); | |||
const compute_resource = item.compute_resource || 'GPU'; | |||
return { | |||
...item, | |||
computeResourceColor: COMPUTER_RESOURCES_COLORS[compute_resource], | |||
computeResourceShow: this.$t('computeResourceTitle.' + compute_resource), | |||
thirdPackagesShow: thirdPackagesList.join('; '), | |||
createTimeStr: formatDate(new Date(item.createdUnix * 1000), 'yyyy-MM-dd HH:mm:ss'), | |||
} | |||
}); | |||
}).catch(err => { | |||
console.log(err); | |||
this.loading = false; | |||
this.list = []; | |||
this.total = 0; | |||
}); | |||
}, | |||
search() { | |||
this.getListData(); | |||
}, | |||
changeImage() { | |||
this.getListData(); | |||
}, | |||
refreshImage(data) { | |||
const find = this.list.find(item => item.id == data.id); | |||
find && Object.assign(find, data); | |||
}, | |||
currentChange(page) { | |||
this.iPage = page; | |||
this.$emit('changeCondition', { | |||
page: this.iPage, | |||
pageSize: this.iPageSize, | |||
changePage: true, | |||
}); | |||
}, | |||
sizeChange(pageSize) { | |||
this.iPageSize = pageSize; | |||
this.$emit('changeCondition', { | |||
page: this.iPage, | |||
pageSize: this.iPageSize, | |||
}); | |||
}, | |||
}, | |||
watch: { | |||
condition: { | |||
handler(newVal) { | |||
this.iPage = newVal.page; | |||
this.iPageSize = newVal.pageSize; | |||
}, | |||
immediate: true, | |||
deep: true, | |||
}, | |||
}, | |||
mounted() { }, | |||
}; | |||
</script> | |||
<style scoped lang="less"> | |||
.list-container { | |||
.list-item-container { | |||
display: flex; | |||
flex-wrap: wrap; | |||
.item-container { | |||
width: 100%; | |||
padding: 12px 0; | |||
} | |||
} | |||
} | |||
.center { | |||
text-align: center; | |||
margin-top: 10px; | |||
} | |||
.no-data { | |||
display: flex; | |||
justify-content: center; | |||
padding: 12px 0; | |||
width: 100%; | |||
.item-empty { | |||
height: 391px; | |||
width: 100%; | |||
overflow: hidden; | |||
padding: 15px; | |||
background: transparent; | |||
display: flex; | |||
flex-direction: column; | |||
justify-content: center; | |||
background-color: rgba(245, 245, 246, 0.5); | |||
.item-empty-icon { | |||
height: 80px; | |||
width: 100%; | |||
background: url(/img/empty-box.svg) center center no-repeat; | |||
} | |||
.item-empty-tips { | |||
text-align: center; | |||
margin-top: 20px; | |||
font-size: 18px; | |||
color: rgb(63, 63, 64); | |||
} | |||
} | |||
} | |||
</style> |
@@ -0,0 +1,99 @@ | |||
<template> | |||
<div class="explore repositories"> | |||
<div class="repos--seach"> | |||
<div class="ui container"> | |||
<div class="search-bar-wrap ui two column centered grid"> | |||
<div class="search-bar fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty"> | |||
<div class="ui fluid action input"> | |||
<input type="text" v-model="condition.q" :placeholder="$t('imagesObj.images_search')" :autofocus="true" | |||
@keyup.enter="conditionChange" /> | |||
<button class="ui green button" @click="conditionChange">{{ $t('repos.search') }}</button> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="ui container"> | |||
<div class="content"> | |||
<div class="content-l"> | |||
<Filters :condition="condition" @changeCondition="conditionChange"></Filters> | |||
</div> | |||
<div class="content-r"> | |||
<Condition :condition="condition" @changeCondition="conditionChange"></Condition> | |||
<List ref="imagesListRef" :condition="condition" @changeCondition="conditionChange"></List> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</template> | |||
<script> | |||
import Filters from './components/Filters.vue'; | |||
import Condition from './components/Condition.vue'; | |||
import List from './components/List.vue'; | |||
import { getUrlSearchParams } from '~/utils'; | |||
export default { | |||
data() { | |||
return { | |||
condition: { | |||
q: '', | |||
tab: '0', | |||
sort: '', | |||
compute_resource: '', | |||
framework: '', | |||
framework_version: '', | |||
python: '', | |||
cuda: '', | |||
page: 1, | |||
pageSize: 15, | |||
}, | |||
pageSizes: [15], | |||
}; | |||
}, | |||
components: { Filters, Condition, List }, | |||
methods: { | |||
conditionChange(params = {}) { | |||
this.condition = { | |||
...this.condition, | |||
...params, | |||
}; | |||
if (!params.changePage) { | |||
this.condition.page = 1; | |||
} | |||
this.$nextTick(() => { | |||
this.$refs.imagesListRef.search(); | |||
}); | |||
}, | |||
}, | |||
beforeMount() { | |||
const urlParams = getUrlSearchParams(); | |||
if (urlParams.type == 'myimage') { | |||
this.condition.tab = '1'; | |||
this.condition.sort = 'newest'; | |||
} | |||
this.$nextTick(() => { | |||
this.$refs.imagesListRef.search(); | |||
}); | |||
}, | |||
mounted() { }, | |||
beforeDestroy() { }, | |||
}; | |||
</script> | |||
<style scoped lang="less"> | |||
.content { | |||
display: flex; | |||
margin-top: -6px; | |||
.content-l { | |||
flex: 1; | |||
padding-left: 12px; | |||
} | |||
.content-r { | |||
margin-left: 10px; | |||
flex: 3; | |||
} | |||
} | |||
</style> |
@@ -0,0 +1,17 @@ | |||
import Vue from 'vue'; | |||
import ElementUI from 'element-ui'; | |||
import 'element-ui/lib/theme-chalk/index.css'; | |||
import localeEn from 'element-ui/lib/locale/lang/en'; | |||
import localeZh from 'element-ui/lib/locale/lang/zh-CN'; | |||
import { i18n, lang } from '~/langs'; | |||
import App from './index.vue'; | |||
Vue.use(ElementUI, { | |||
locale: lang === 'zh-CN' ? localeZh : localeEn, | |||
size: 'small', | |||
}); | |||
new Vue({ | |||
i18n, | |||
render: (h) => h(App), | |||
}).$mount('#__vue-root'); |
@@ -0,0 +1,716 @@ | |||
<template> | |||
<div> | |||
<div class="ui container"> | |||
<div class="form-container" v-loading="submitLoading"> | |||
<div class="form-head"> | |||
<h4 v-if="pageType == 'edit'">{{ $t('imagesObj.editImage') }}</h4> | |||
<h4 v-if="pageType == 'submit' || pageType == 'submitAdmin'">{{ $t('imagesObj.submitImage') }}</h4> | |||
<h4 v-if="pageType == 'apply'">{{ $t('imagesObj.appyImage') }}</h4> | |||
</div> | |||
<div class="form-body"> | |||
<div class="form-body-content"> | |||
<div class="form-row form-row-cluster" v-show="false"> | |||
<div class="title align-items-center"><span class="required">{{ $t('modelManage.useCluster') }}</span> | |||
</div> | |||
<div class="content"> | |||
<div class="list"> | |||
<a class="item" href="javascript:;" v-for="item in typeList" :key="item.k" @click="changeType(item)" | |||
:class="form.type == item.k ? 'focus' : ''"> | |||
<i class="icon ri-archive-drawer-line"></i> | |||
<span>{{ item.v }}</span> | |||
</a> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="form-row"> | |||
<div class="title"><span class="required">{{ $t('imagesObj.imageTag') }}</span></div> | |||
<div class="content" :class="errors.tag ? 'error' : ''"> | |||
<el-input class="field-input" :disabled="pageType != 'submit' && pageType != 'submitAdmin'" | |||
v-model="form.tag" @blur="checkTag" @input="checkTag" :maxlength="50" | |||
:placeholder="$t('imagesObj.imageTagPlaceholder')" :autofocus="true"></el-input> | |||
<div class="tips">{{ $t('imagesObj.imageTagInputTips') }}</div> | |||
</div> | |||
</div> | |||
<div class="form-row"> | |||
<div class="title"><span class="required">{{ $t('cloudbrainObj.computeResource') }}</span></div> | |||
<div class="content"> | |||
<el-select class="field-input" v-model="form.compute_resource" :disabled="pageType != 'submitAdmin'" | |||
@change="changeComputeResource"> | |||
<el-option v-for="item in computeResourceList" :key="item.k" :value="item.k" | |||
:label="item.v"></el-option> | |||
</el-select> | |||
</div> | |||
</div> | |||
<div class="form-row" v-if="pageType == 'submitAdmin'"> | |||
<div class="title"><span :class="form.compute_resource == 'GPU' ? 'required' : ''">{{ | |||
$t('imagesObj.imageAdress') }}</span></div> | |||
<div class="content" :class="errors.place ? 'error' : ''"> | |||
<el-input class="field-input" v-model="form.place" @blur="checkNull('place')" | |||
@input="checkNull('place')" :maxlength="300" | |||
:placeholder="$t('imagesObj.imageAdressPlaceholder')"></el-input> | |||
</div> | |||
</div> | |||
<div class="form-row" v-if="pageType == 'submitAdmin' || (pageType == 'edit' && pageFrom == 'imageAdmin')"> | |||
<div class="title"><span>{{ $t('resourcesManagement.aiCenter') }}</span></div> | |||
<div class="content"> | |||
<el-input class="field-input" type="textarea" v-model="form.aICenterImage" :maxlength="1500" :rows="3" | |||
:placeholder="$t('imagesObj.imageAiCenterPlaceholder')"></el-input> | |||
</div> | |||
</div> | |||
<div class="form-row"> | |||
<div class="left"> | |||
<div class="title"><span class="required">{{ $t('imagesObj.frameworkName') }}</span></div> | |||
<div class="content" :class="errors.framework ? 'error' : ''"> | |||
<el-select class="field-input" v-model="form.framework" @change="changeFramework"> | |||
<el-option v-for="item in frameworkList" :key="item.k" :value="item.k" :label="item.v"></el-option> | |||
</el-select> | |||
</div> | |||
</div> | |||
<div class="right"> | |||
<div v-show="frameworkVersionList.length" class="title"><span class="required">{{ | |||
$t('imagesObj.version') | |||
}}</span></div> | |||
<div v-show="frameworkVersionList.length" class="content" | |||
:class="errors.framework_version ? 'error' : ''"> | |||
<el-select class="field-input" v-model="form.framework_version" | |||
@change="checkNull('framework_version')"> | |||
<el-option v-for="item in frameworkVersionList" :key="item.k" :value="item.k" | |||
:label="item.v"></el-option> | |||
</el-select> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="form-row"> | |||
<div class="title"><span class="required">{{ $t('imagesObj.pyVersion') }}</span></div> | |||
<div class="content" :class="errors.python ? 'error' : ''"> | |||
<el-select class="field-input" v-model="form.python" @change="checkNull('python')"> | |||
<el-option v-for="item in pythonList" :key="item.k" :value="item.k" :label="item.v"></el-option> | |||
</el-select> | |||
</div> | |||
</div> | |||
<div class="form-row" v-if="form.compute_resource == 'GPU'"> | |||
<div class="title"><span class="required">{{ $t('imagesObj.cudaVersion') }}</span></div> | |||
<div class="content" :class="errors.cuda ? 'error' : ''"> | |||
<el-select class="field-input" v-model="form.cuda" @change="checkNull('cuda')"> | |||
<el-option v-for="item in cudaList" :key="item.k" :value="item.k" :label="item.v"></el-option> | |||
</el-select> | |||
</div> | |||
</div> | |||
<div class="form-row"> | |||
<div class="left"> | |||
<div class="title"><span>{{ $t('imagesObj.operationSystemName') }}</span></div> | |||
<div class="content"> | |||
<el-input class="field-input" v-model="form.operationSystem" :maxlength="100" | |||
:placeholder="$t('imagesObj.operationSystemNamePlaceholder')"></el-input> | |||
</div> | |||
</div> | |||
<div class="right"> | |||
<div class="title"><span>{{ $t('imagesObj.version') }}</span></div> | |||
<div class="content"> | |||
<el-input class="field-input" v-model="form.operationSystemVersion" :maxlength="50" | |||
:placeholder="$t('imagesObj.operationSystemVersionPlaceholder')"></el-input> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="form-row"> | |||
<div class="title"><span>{{ $t('imagesObj.thirdPackages') }}</span></div> | |||
<div class="content"> | |||
<el-input class="field-input" type="textarea" v-model="form.thirdPackages" :rows="3" | |||
@blur="checkThirdPackages" :placeholder="$t('imagesObj.thirdPackagesPlaceholder')" | |||
:maxlength="1000"></el-input> | |||
</div> | |||
</div> | |||
<div class="form-row"> | |||
<div class="title"><span>{{ $t('imagesObj.topic') }}</span></div> | |||
<div class="content"> | |||
<el-select class="field-input topic-input" popper-class="popper-topic-input" v-model="form.topics" | |||
remote :remote-method="topicRemoteMethod" :loading="topicLoading" multiple filterable allow-create | |||
default-first-option clearable :placeholder="$t('imagesObj.topicPlaceholder')"> | |||
<el-option v-for="item in topicList" :key="item.k" :value="item.k" :label="item.v"></el-option> | |||
</el-select> | |||
<div class="tips tips-ext"> | |||
<i class="ri-error-warning-line"></i> | |||
<span v-html="$t('imagesObj.topicTips')"></span> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="form-row"> | |||
<div class="title"><span class="required">{{ $t('imagesObj.descr') }}</span></div> | |||
<div class="content" :class="errors.description ? 'error' : ''"> | |||
<el-input class="field-input" type="textarea" v-model="form.description" :rows="3" | |||
@blur="checkNull('description')" @input="checkNull('description')" | |||
:placeholder="$t('imagesObj.descrPlaceholder')" :maxlength="1000"></el-input> | |||
</div> | |||
</div> | |||
<div class="form-row" style="margin-top:-10px" v-if="pageType == 'submitAdmin'"> | |||
<div class="title"><span></span></div> | |||
<div class="content" style="padding-top:8px"> | |||
<el-radio-group v-model="form.isRecommend"> | |||
<el-radio label="true">{{ $t('imagesObj.recommend') }}</el-radio> | |||
<el-radio label="false">{{ $t('imagesObj.notRecommend') }}</el-radio> | |||
</el-radio-group> | |||
</div> | |||
</div> | |||
<div class="form-row" style="margin-top:-10px"> | |||
<div class="title"><span></span></div> | |||
<div class="content"> | |||
<div class="tips tips-ext" style="font-size:14px;"> | |||
<i class="ri-error-warning-line"></i> | |||
<span> | |||
<span class="light" v-html="$t('imagesObj.submitTips')"></span> | |||
</span> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="form-row"> | |||
<div class="title"></div> | |||
<div class="content"> | |||
<el-button type="primary" size="default" class="submit-btn" @click="submit">{{ | |||
pageType == 'apply' ? $t('imagesObj.submitApply') : $t('submit') }}</el-button> | |||
<el-button class="cancel-btn" size="default" @click="cancel">{{ $t('cancel') }}</el-button> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</template> | |||
<script> | |||
import { getStaticFile } from '~/apis/modules/common'; | |||
import { searchImageTopics, submitImage } from '~/apis/modules/images'; | |||
import { i18n } from '~/langs'; | |||
export default { | |||
data() { | |||
return { | |||
pageType: window._PageType, // submit|submitAdmin|edit|apply | |||
pageFrom: window._PageFrom, // submit|imageSquare|imageAdmin|apply | |||
pageSubmitLink: window._PageSubmitLink, | |||
pageRepoLink: window._PageRepoLink, | |||
originData: {}, | |||
form: { | |||
type: window._ImageType || '2', // 0启智GPU|2智算GPU | |||
tag: '', | |||
compute_resource: window._ImageComputeResource || 'GPU', | |||
place: '', | |||
aICenterImage: '', | |||
framework: '', | |||
framework_version: '', | |||
python: '', | |||
cuda: '', | |||
operationSystem: '', | |||
operationSystemVersion: '', | |||
thirdPackages: '', | |||
topics: [], | |||
description: '', | |||
isRecommend: 'true', | |||
}, | |||
typeList: [{ k: '0', v: i18n.t('imagesObj.openIGPU') }, { k: '2', v: i18n.t('imagesObj.c2netGPU') }], | |||
computeResourceList: [], | |||
topicLoading: false, | |||
topicList: [], | |||
frameworkList: [], | |||
frameworkVersionList: [], | |||
pythonList: [], | |||
cudaList: [], | |||
condtionsData: {}, | |||
errors: { | |||
tag: false, | |||
place: false, | |||
framework: false, | |||
framework_version: false, | |||
python: false, | |||
cuda: false, | |||
description: false, | |||
}, | |||
submitLoading: false, | |||
}; | |||
}, | |||
components: {}, | |||
methods: { | |||
changeType(item) { | |||
this.form.type = item.k; | |||
}, | |||
checkTag() { | |||
this.form.tag = this.form.tag.trim(); | |||
const reg = /^[a-zA-Z][\w|\-|\.]*$/; | |||
this.errors.tag = !reg.test(this.form.tag); | |||
return this.errors.tag; | |||
}, | |||
checkNull(key) { | |||
this.form[key] = this.form[key]; | |||
this.errors[key] = !this.form[key]; | |||
if (key == 'place' && this.form.compute_resource != 'GPU') { | |||
this.errors[key] = false; | |||
} | |||
return this.errors[key]; | |||
}, | |||
checkThirdPackages() { | |||
const last = this.form.thirdPackages.slice(-1) == '\n' ? '\n' : ''; | |||
const lines = this.form.thirdPackages.split('\n'); | |||
this.form.thirdPackages = lines.map(item => item.trim()).filter(item => item).slice(0, 10).join('\n') + last; | |||
}, | |||
changeComputeResource() { | |||
if (this.form.compute_resource == 'GPU') { | |||
this.form.cuda = this.cudaList.length ? this.cudaList[0].k : ''; | |||
} else { | |||
this.form.cuda = ''; | |||
this.errors.cuda = false; | |||
this.errors.place = false; | |||
} | |||
}, | |||
changeFramework(framework) { | |||
const versions = (this.condtionsData['framework_version'][framework] || []).map(item => { | |||
return { | |||
k: item, | |||
v: item, | |||
}; | |||
}); | |||
this.form.framework_version = ''; | |||
this.frameworkVersionList = versions; | |||
if (versions.length) { | |||
this.form.framework_version = versions[0].k; | |||
} else { | |||
this.form.framework_version = ''; | |||
} | |||
this.checkNull('framework'); | |||
}, | |||
topicRemoteMethod(query) { | |||
if (query !== '') { | |||
this.topicLoading = true; | |||
searchImageTopics({ q: query }).then(res => { | |||
this.topicLoading = false; | |||
res = res.data; | |||
if (res.topics) { | |||
this.topicList = []; | |||
const find = res.topics.find(item => item.topic_name === query); | |||
find && this.topicList.push({ k: find.topic_name, v: find.topic_name }); | |||
for (let i = 0, iLen = res.topics.length; i < iLen; i++) { | |||
const topic = res.topics[i]; | |||
if (!find || topic.topic_name !== find.topic_name) { | |||
this.topicList.push({ | |||
k: topic.topic_name, | |||
v: topic.topic_name | |||
}); | |||
} | |||
} | |||
} else { | |||
this.topicList = []; | |||
} | |||
}).catch(err => { | |||
this.topicLoading = false; | |||
this.topicList = []; | |||
console.log(err); | |||
}); | |||
} else { | |||
this.topicList = []; | |||
} | |||
}, | |||
submit() { | |||
let hasError = false; | |||
for (let key in this.errors) { | |||
let isError = false; | |||
if (this.pageType == 'submit' && key == 'place') continue; | |||
if (key == 'place' && this.form.compute_resource != 'GPU') continue; | |||
if (key == 'tag') { | |||
isError = this.checkTag(); | |||
} else if (key == 'framework_version') { | |||
if (this.frameworkVersionList.length) { | |||
isError = this.checkNull(key); | |||
} | |||
} else if (key == 'cuda') { | |||
if (this.form.compute_resource == 'GPU') { | |||
isError = this.checkNull(key); | |||
} | |||
} else { | |||
isError = this.checkNull(key); | |||
} | |||
if (isError) { | |||
hasError = true; | |||
} | |||
} | |||
if (hasError) return; | |||
const subData = { | |||
link: this.pageSubmitLink, | |||
type: this.form.type, | |||
tag: this.form.tag.trim(), | |||
computeResource: this.form.compute_resource, | |||
framework: this.form.framework, | |||
frameworkVersion: this.form.framework_version, | |||
cudaVersion: this.form.cuda, | |||
pythonVersion: this.form.python, | |||
operationSystem: this.form.operationSystem.trim(), | |||
operationSystemVersion: this.form.operationSystemVersion.trim(), | |||
thirdPackages: this.form.thirdPackages.trim(), | |||
topics: this.form.topics.join(','), | |||
description: this.form.description.trim(), | |||
}; | |||
if (this.pageType == 'edit' || this.pageType == 'apply') { | |||
subData.id = this.originData.id; | |||
} | |||
if (this.pageType == 'submitAdmin') { | |||
subData.isRecommend = this.form.isRecommend; | |||
subData.place = this.form.place; | |||
} | |||
if (this.pageType == 'submitAdmin' || (this.pageType == 'edit' && this.pageFrom == 'imageAdmin')) { | |||
subData.aICenterImage = this.form.aICenterImage; | |||
} | |||
// console.log('submit subData', this.pageSubmitLink, this.pageRepoLink, subData); | |||
// return; | |||
this.submitLoading = true; | |||
submitImage(subData).then(res => { | |||
res = res.data; | |||
if (res.Code == 0) { | |||
this.$message({ | |||
type: 'success', | |||
message: this.$t('submittedSuccessfully'), | |||
}); | |||
setTimeout(() => { | |||
this.cancel('success'); | |||
}, 200); | |||
} else { | |||
this.submitLoading = false; | |||
this.$message({ | |||
type: 'error', | |||
message: res.Message, | |||
}); | |||
} | |||
}).catch(err => { | |||
this.submitLoading = false; | |||
console.log(err); | |||
this.$message({ | |||
type: 'error', | |||
message: this.$t('submittedFailed'), | |||
}); | |||
}); | |||
}, | |||
cancel(status) { | |||
if (this.pageFrom == 'submit') { | |||
if (status == 'success') { | |||
location.href = `/explore/images?type=myimage`; | |||
} else { | |||
window.close(); | |||
} | |||
} else if (this.pageFrom == 'imageSquare' || this.pageFrom == 'apply') { | |||
location.href = `/explore/images?type=myimage`; | |||
} else if (this.pageFrom == 'imageAdmin') { | |||
location.href = `/admin/images` + window.location.search; | |||
} | |||
} | |||
}, | |||
beforeMount() { | |||
if (this.pageType == 'submit') { | |||
this.typeList = this.typeList.filter(item => item.k == this.form.type); | |||
} | |||
if (this.pageType == 'submitAdmin') { | |||
this.form.type = '2'; | |||
this.form.compute_resource = 'GPU'; | |||
this.typeList = this.typeList.filter(item => item.k == this.form.type); | |||
} | |||
if (this.pageType == 'edit' || this.pageType == 'apply') { | |||
const image = window._Image || {}; | |||
this.originData = image; | |||
this.form.type = image.cloudbrainType.toString(); | |||
this.typeList = this.typeList.filter(item => item.k == this.form.type); | |||
this.form.tag = image.tag; | |||
this.form.compute_resource = image.compute_resource || 'GPU'; | |||
this.form.place = image.place; | |||
this.form.aICenterImage = JSON.stringify(image.AiCenterImages || []); | |||
this.form.operationSystem = image.operationSystem; | |||
this.form.operationSystemVersion = image.operationSystemVersion; | |||
this.form.thirdPackages = image.thirdPackages; | |||
this.form.topics = image.topics || []; | |||
this.form.description = image.description; | |||
} | |||
getStaticFile('/images_version.json').then(res => { | |||
const data = res.data; | |||
if (data) { | |||
this.condtionsData = data; | |||
this.frameworkList = (data.framework || []).map(item => { | |||
return { k: item, v: item }; | |||
}); | |||
this.form.framework = this.frameworkList.length ? this.frameworkList[0].k : ''; | |||
this.changeFramework(this.form.framework); | |||
this.cudaList = (data.cuda || []).map(item => { | |||
return { k: item, v: `Cuda ${item}` }; | |||
}); | |||
this.form.cuda = this.cudaList.length ? this.cudaList[0].k : ''; | |||
this.pythonList = (data.python || []).map(item => { | |||
return { k: item, v: `Python ${item}` }; | |||
}); | |||
this.form.python = this.pythonList.length ? this.pythonList[0].k : ''; | |||
if (this.pageType == 'edit' || this.pageType == 'apply') { | |||
const image = window._Image || {}; | |||
this.form.framework = image.framework; | |||
this.changeFramework(this.form.framework); | |||
this.form.framework_version = image.frameworkVersion; | |||
this.form.cuda = image.cudaVersion; | |||
this.form.python = image.pythonVersion; | |||
} | |||
this.computeResourceList = (data.compute_resource || []).map(item => { | |||
return { k: item, v: this.$t('computeResourceTitle.' + item) || item }; | |||
}); | |||
} | |||
}).catch(err => { | |||
console.log(err); | |||
}); | |||
}, | |||
mounted() { }, | |||
beforeDestroy() { }, | |||
}; | |||
</script> | |||
<style scoped lang="less"> | |||
.form-container { | |||
.form-head { | |||
background: #f0f0f0; | |||
border-radius: 0.28571429rem 0.28571429rem 0 0; | |||
padding: 0.78571429rem 1rem; | |||
margin: 0 -1px; | |||
box-shadow: none; | |||
border: 1px solid #d4d4d5; | |||
} | |||
.form-body { | |||
min-height: 400px; | |||
border: 1px solid #d4d4d5; | |||
margin: -1px -1px; | |||
padding: 3em; | |||
background-color: #FFF; | |||
.form-body-content { | |||
max-width: 1200px; | |||
margin: 0 auto; | |||
padding-right: 120px; | |||
.form-row { | |||
display: flex; | |||
margin-bottom: 28px; | |||
.left { | |||
display: flex; | |||
width: 65%; | |||
} | |||
.right { | |||
display: flex; | |||
width: 35%; | |||
.title { | |||
width: 100px; | |||
} | |||
} | |||
.title { | |||
width: 200px; | |||
text-align: right; | |||
margin-right: 24px; | |||
color: #101010; | |||
font-size: 14px; | |||
display: flex; | |||
justify-content: flex-end; | |||
padding-top: 8px; | |||
flex-shrink: 0; | |||
&.align-items-center { | |||
padding-top: 0; | |||
align-items: center; | |||
} | |||
.required { | |||
position: relative; | |||
&::after { | |||
position: absolute; | |||
content: "*"; | |||
top: -3px; | |||
right: -10px; | |||
color: red; | |||
} | |||
} | |||
} | |||
.content { | |||
flex: 1; | |||
.field-input { | |||
width: 100%; | |||
} | |||
.tips { | |||
font-size: 12px; | |||
color: rgba(136, 136, 136, 1); | |||
margin-top: 10px; | |||
&.tips-ext { | |||
display: flex; | |||
font-size: 12px; | |||
align-items: center; | |||
i { | |||
color: #f2711c; | |||
margin-right: 5px; | |||
font-size: 14px; | |||
} | |||
/deep/.light, | |||
.light { | |||
color: #f2711c; | |||
} | |||
} | |||
} | |||
.field-input { | |||
/deep/.el-input__inner { | |||
height: 37.6px; | |||
} | |||
/deep/.el-input__inner, | |||
/deep/.el-textarea__inner { | |||
color: rgba(0, 0, 0, .95); | |||
font-size: 14px; | |||
line-height: 22px; | |||
&:visited { | |||
border-color: #85b7d9; | |||
} | |||
&:focus { | |||
border-color: #85b7d9; | |||
} | |||
&:active { | |||
border-color: #85b7d9; | |||
} | |||
} | |||
} | |||
.topic-input { | |||
/deep/.el-input.is-focus .el-input__inner { | |||
border-color: #85b7d9; | |||
} | |||
} | |||
&.error { | |||
.field-input { | |||
/deep/.el-input__inner, | |||
/deep/.el-textarea__inner { | |||
color: #9f3a38; | |||
background: #fff6f6; | |||
border-color: #e0b4b4; | |||
&:visited { | |||
border-color: #e0b4b4; | |||
} | |||
&:focus { | |||
border-color: #e0b4b4; | |||
} | |||
&:active { | |||
border-color: #e0b4b4; | |||
} | |||
} | |||
} | |||
} | |||
.list { | |||
display: flex; | |||
align-items: center; | |||
flex-wrap: wrap; | |||
.item { | |||
display: flex; | |||
align-items: center; | |||
justify-content: center; | |||
font-size: 12px; | |||
color: rgba(0, 0, 0, .87); | |||
border: 1px solid rgba(34, 36, 38, .15); | |||
margin-left: -1px; | |||
height: 38px; | |||
padding: 0 12px; | |||
border-left: none; | |||
margin-bottom: 5px; | |||
i { | |||
margin-top: -7px; | |||
font-size: 14px; | |||
} | |||
&.focus { | |||
color: #0087f5; | |||
border-color: #0087f5; | |||
border-left: 1px solid #0087f5; | |||
} | |||
&:first-child { | |||
border-top-left-radius: 0.28571429rem; | |||
border-bottom-left-radius: 0.28571429rem; | |||
border-left: 1px solid rgba(34, 36, 38, .15); | |||
&.focus { | |||
border-color: #0087f5; | |||
} | |||
} | |||
&:last-child { | |||
border-top-right-radius: 0.28571429rem; | |||
border-bottom-right-radius: 0.28571429rem; | |||
} | |||
&:hover:not(.focus) { | |||
background: rgba(0, 0, 0, .03); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
.submit-btn { | |||
background-color: #5bb973; | |||
color: #fff; | |||
border-color: #5bb973; | |||
&:hover { | |||
background-color: #16ab39; | |||
} | |||
&:active { | |||
background-color: #198f35; | |||
} | |||
&.is-disabled, | |||
&.is-disabled:active, | |||
&.is-disabled:focus, | |||
&.is-disabled:hover { | |||
background-color: #5bb973; | |||
opacity: .45; | |||
} | |||
a { | |||
color: #fff; | |||
font-weight: 700; | |||
} | |||
} | |||
.cancel-btn { | |||
background: #e0e1e2; | |||
color: rgba(0, 0, 0, .6); | |||
border-color: #e0e1e2; | |||
&:hover { | |||
background-color: #cacbcd; | |||
} | |||
&:active { | |||
background-color: #babbbc; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
</style> |
@@ -0,0 +1,17 @@ | |||
import Vue from 'vue'; | |||
import ElementUI from 'element-ui'; | |||
import 'element-ui/lib/theme-chalk/index.css'; | |||
import localeEn from 'element-ui/lib/locale/lang/en'; | |||
import localeZh from 'element-ui/lib/locale/lang/zh-CN'; | |||
import { i18n, lang } from '~/langs'; | |||
import App from './index.vue'; | |||
Vue.use(ElementUI, { | |||
locale: lang === 'zh-CN' ? localeZh : localeEn, | |||
size: 'small', | |||
}); | |||
new Vue({ | |||
i18n, | |||
render: (h) => h(App), | |||
}).$mount('#__vue-root'); |
Dear OpenI User
Thank you for your continuous support to the Openl Qizhi Community AI Collaboration Platform. In order to protect your usage rights and ensure network security, we updated the Openl Qizhi Community AI Collaboration Platform Usage Agreement in January 2024. The updated agreement specifies that users are prohibited from using intranet penetration tools. After you click "Agree and continue", you can continue to use our services. Thank you for your cooperation and understanding.
For more agreement content, please refer to the《Openl Qizhi Community AI Collaboration Platform Usage Agreement》