#4535 fix-4436

Merged
ychao_1983 merged 31 commits from fix-4436 into V20230718 9 months ago
  1. +5
    -1
      entity/ai_task.go
  2. +3
    -1
      models/action.go
  3. +10
    -4
      models/cloudbrain.go
  4. +16
    -13
      models/task_config.go
  5. +3
    -0
      modules/setting/setting.go
  6. +5
    -0
      options/locale/locale_en-US.ini
  7. +5
    -0
      options/locale/locale_zh-CN.ini
  8. +6
    -1
      public/home/home.js
  9. BIN
      public/img/supercompute/mmlspark.jpg
  10. +3
    -2
      routers/repo/cloudbrain.go
  11. +1
    -0
      routers/repo/modelarts.go
  12. +8
    -0
      routers/routes/routes.go
  13. +33
    -0
      routers/super_compute/super_compute.go
  14. +5
    -1
      services/ai_task_service/task/grampus_notebook_task.go
  15. +1
    -0
      services/ai_task_service/task/opt_handler.go
  16. +88
    -0
      services/ai_task_service/task/super_compute_task.go
  17. +9
    -2
      services/ai_task_service/task/task_base.go
  18. +5
    -3
      services/ai_task_service/task/task_creation_info.go
  19. +1
    -0
      services/ai_task_service/task/task_service.go
  20. +1
    -1
      services/socketwrap/clientManager.go
  21. +24
    -4
      templates/admin/cloudbrain/list.tmpl
  22. +3
    -1
      templates/admin/cloudbrain/search.tmpl
  23. +4
    -2
      templates/admin/cloudbrain/search_dashboard.tmpl
  24. +9
    -1
      templates/repo/header.tmpl
  25. +8
    -0
      templates/repo/supercompute/create.tmpl
  26. +8
    -0
      templates/repo/supercompute/detail.tmpl
  27. +8
    -0
      templates/repo/supercompute/index.tmpl
  28. +8
    -0
      templates/repo/supercompute/list.tmpl
  29. +25
    -4
      templates/user/dashboard/cloudbrains.tmpl
  30. +9
    -1
      templates/user/dashboard/feeds.tmpl
  31. +2
    -0
      web_src/js/features/cloudrbanin.js
  32. +1
    -0
      web_src/vuepages/apis/modules/cloudbrain.js
  33. +11
    -5
      web_src/vuepages/components/cloudbrain/TaskName.vue
  34. +6
    -0
      web_src/vuepages/components/cloudbrain/details/ConfigInfo.vue
  35. +2
    -2
      web_src/vuepages/const/index.js
  36. +12
    -1
      web_src/vuepages/langs/config/en-US.js
  37. +12
    -0
      web_src/vuepages/langs/config/zh-CN.js
  38. +7
    -7
      web_src/vuepages/pages/resources/components/SpecSelect.vue
  39. +186
    -0
      web_src/vuepages/pages/supercompute/apps/index.vue
  40. +17
    -0
      web_src/vuepages/pages/supercompute/apps/vp-cloudbrain-super-apps.js
  41. +94
    -0
      web_src/vuepages/pages/supercompute/configs.js
  42. +406
    -0
      web_src/vuepages/pages/supercompute/create/index.vue
  43. +17
    -0
      web_src/vuepages/pages/supercompute/create/vp-cloudbrain-super-create.js
  44. +332
    -0
      web_src/vuepages/pages/supercompute/detail/index.vue
  45. +17
    -0
      web_src/vuepages/pages/supercompute/detail/vp-cloudbrain-super-detail.js
  46. +559
    -0
      web_src/vuepages/pages/supercompute/list/index.vue
  47. +17
    -0
      web_src/vuepages/pages/supercompute/list/vp-cloudbrain-super-list.js
  48. +6
    -4
      web_src/vuepages/utils/index.js

+ 5
- 1
entity/ai_task.go View File

@@ -18,7 +18,7 @@ import (
"code.gitea.io/gitea/modules/timeutil"
)

//todo 暂时保留之前各种云脑属性的定义
// todo 暂时保留之前各种云脑属性的定义
type CreateReq struct {
JobType models.JobType `json:"job_type" binding:"Required"`
DisplayJobName string `json:"display_job_name" binding:"Required"`
@@ -44,6 +44,7 @@ type CreateReq struct {
PoolId string `json:"pool_id"`
IsContinueRequest bool `json:"is_continue"`
SourceCloudbrainId int64 `json:"source_cloudbrain_id"`
AppName string `json:"app_name"`
ParamArray models.Parameters
ComputeSource *models.ComputeSource
ReqCommitID string
@@ -139,6 +140,7 @@ type AITaskDetailInfo struct {
EngineName string `json:"engine_name"`
FailedReason string `json:"failed_reason"`
UserId int64 `json:"-"`
AppName string `json:"app_name"`
}

func (a *AITaskDetailInfo) Tr(language string) {
@@ -207,6 +209,7 @@ type AITaskBriefInfo struct {
AICenter string `json:"ai_center"`
IsFileNotebook bool `json:"is_file_notebook"`
IsFineTuneTask bool `json:"is_fine_tune_task"`
APPName string `json:"app_name"`
}

func (a *AITaskBriefInfo) Tr(language string) {
@@ -243,6 +246,7 @@ func ConvertCloudbrainToAITaskBriefInfo(task *models.Cloudbrain) *AITaskBriefInf
AICenter: task.AiCenter,
IsFileNotebook: task.IsFileNoteBookTask(),
IsFineTuneTask: task.FineTune,
APPName: task.AppName,
}
}



+ 3
- 1
models/action.go View File

@@ -73,6 +73,7 @@ const (
ActionCreateGrampusMLUTrainTask //44
ActionCreateGrampusGPUOnlineInferTask //45
ActionCreateGrampusDCUDebugTask //46
ActionCreateSuperComputeTask //47
)

// Action represents user operation type and other information to
@@ -425,7 +426,8 @@ func (a *Action) IsCloudbrainAction() bool {
ActionCreateGrampusGCUTrainTask,
ActionCreateGrampusGCUDebugTask,
ActionCreateGrampusDCUDebugTask,
ActionCreateGrampusMLUDebugTask:
ActionCreateGrampusMLUDebugTask,
ActionCreateSuperComputeTask:
return true
}
return false


+ 10
- 4
models/cloudbrain.go View File

@@ -48,6 +48,7 @@ const (
NPUResource = "NPU"
GPUResource = "CPU/GPU"
GCUResource = "GCU"
CPUResource = "CPU"
AllResource = "all"

//notebook storage category
@@ -78,6 +79,7 @@ const (
JobTypeTrain JobType = "TRAIN"
JobTypeInference JobType = "INFERENCE"
JobTypeOnlineInference JobType = "ONLINEINFERENCE"
JobTypeSuperCompute JobType = "SUPERCOMPUTE"

//notebook
ModelArtsCreateQueue ModelArtsJobStatus = "CREATE_QUEUING" //免费资源创建排队中
@@ -158,12 +160,14 @@ const (
GCU = "GCU"
MLU = "MLU"
DCU = "DCU"
CPU = "CPU"

ProcessorTypeNPU = "npu.huawei.com/NPU"
ProcessorTypeGPU = "nvidia.com/gpu"
ProcessorTypeGCU = "enflame-tech.com/gcu"
ProcessorTypeMLU = "cambricon.com/mlu"
ProcessorTypeDCU = "ac.sugon.com/dcu"
ProcessorTypeCPU = "hpc/cpu"
)

const CloudbrainTwoDefaultVersion = "/V0001"
@@ -212,6 +216,7 @@ var ComputeSourceMap = map[string]*ComputeSource{
GCU: {Name: GCU, FullName: ProcessorTypeGCU},
MLU: {Name: MLU, FullName: ProcessorTypeMLU},
DCU: {Name: DCU, FullName: ProcessorTypeDCU},
CPU: {Name: CPU, FullName: ProcessorTypeCPU},
}

const (
@@ -298,6 +303,7 @@ type Cloudbrain struct {
FineTuneCategory int
Spec *Specification `xorm:"-"`
Config *CloudbrainConfig `xorm:"-"`
AppName string //超算任务的应用类型
}

type CloudbrainShow struct {
@@ -397,7 +403,7 @@ func (task *Cloudbrain) GetAiCenter() string {

}

//是否为在线notebook文件任务
// 是否为在线notebook文件任务
func (task *Cloudbrain) IsFileNoteBookTask() bool {
return task.JobType == string(JobTypeDebug) && task.BootFile != ""
}
@@ -481,8 +487,8 @@ func (task *Cloudbrain) NeedActiveStop() bool {
return task.IsCreating() || (task.IsPreparing() && int64(task.CreatedUnix) < time.Now().Add(-1*setting.PREPARING_MAX_WAIT_DURATION).Unix())
}

//是否允许创建多版本
//目前只有启智NPU可以
// 是否允许创建多版本
// 目前只有启智NPU可以
func (task *Cloudbrain) IsAllowedToCreateMultipleVersions() bool {
if task.Type == TypeCloudBrainTwo && task.ComputeResource == NPUResource && task.JobType != string(JobTypeDebug) {
return true
@@ -3241,7 +3247,7 @@ func GetDatasetInfo(uuidStr string, grampusType ...string) (map[string]DatasetIn
dataLocalPath = setting.Attachment.Minio.BasePath + path.Join(attach.UUID[0:1], attach.UUID[1:2]) + "/" + attach.UUID
} else if grampusType[0] == NPU {
dataLocalPath = setting.BasePath + path.Join(attach.UUID[0:1], attach.UUID[1:2]) + "/" + attach.UUID + "/"
} else if grampusType[0] == GCU || grampusType[0] == MLU || grampusType[0] == DCU {
} else {
if attach.Type == TypeCloudBrainOne {
dataLocalPath = setting.Attachment.Minio.BasePath + path.Join(attach.UUID[0:1], attach.UUID[1:2]) + "/" + attach.UUID
} else {


+ 16
- 13
models/task_config.go View File

@@ -13,19 +13,20 @@ const (
type TaskType string

const (
TaskCreatePublicRepo TaskType = "CreatePublicRepo"
TaskCreateIssue TaskType = "CreateIssue"
TaskCreatePullRequest TaskType = "CreatePullRequest"
TaskCommentIssue TaskType = "CommentIssue"
TaskUploadAttachment TaskType = "UploadAttachment"
TaskCreateNewModelTask TaskType = "CreateNewModelTask"
TaskBindWechat TaskType = "BindWechat"
TaskCreateCloudbrainTask TaskType = "CreateCloudbrainTask"
TaskDatasetRecommended TaskType = "DatasetRecommended"
TaskCreateImage TaskType = "CreateImage"
TaskImageRecommend TaskType = "ImageRecommend"
TaskChangeUserAvatar TaskType = "ChangeUserAvatar"
TaskPushCommits TaskType = "PushCommits"
TaskCreatePublicRepo TaskType = "CreatePublicRepo"
TaskCreateIssue TaskType = "CreateIssue"
TaskCreatePullRequest TaskType = "CreatePullRequest"
TaskCommentIssue TaskType = "CommentIssue"
TaskUploadAttachment TaskType = "UploadAttachment"
TaskCreateNewModelTask TaskType = "CreateNewModelTask"
TaskBindWechat TaskType = "BindWechat"
TaskCreateCloudbrainTask TaskType = "CreateCloudbrainTask"
TaskCreateSuperComputeTask TaskType = "CreateSuperComputeTask"
TaskDatasetRecommended TaskType = "DatasetRecommended"
TaskCreateImage TaskType = "CreateImage"
TaskImageRecommend TaskType = "ImageRecommend"
TaskChangeUserAvatar TaskType = "ChangeUserAvatar"
TaskPushCommits TaskType = "PushCommits"
)

func GetTaskTypeFromAction(a ActionType) TaskType {
@@ -46,6 +47,8 @@ func GetTaskTypeFromAction(a ActionType) TaskType {
ActionCreateGrampusGPUOnlineInferTask,
ActionCreateGrampusGPUTrainTask:
return TaskCreateCloudbrainTask
case ActionCreateSuperComputeTask:
return TaskCreateSuperComputeTask
case ActionCreateRepo:
return TaskCreatePublicRepo
case ActionCreatePullRequest:


+ 3
- 0
modules/setting/setting.go View File

@@ -641,6 +641,7 @@ var (
UsageRateBeginTime string
GPUImageCommonName string
MultiNode string
MMLSparkMaxTime int64
}{}

ClearStrategy = struct {
@@ -1894,6 +1895,8 @@ func GetGrampusConfig() {
}
Grampus.MultiNode = sec.Key("MULTI_NODE").MustString("")

Grampus.MMLSparkMaxTime = sec.Key("MMLSparkMaxTime").MustInt64(8 * 3600)

}

func SetRadarMapConfig() {


+ 5
- 0
options/locale/locale_en-US.ini View File

@@ -1096,6 +1096,7 @@ online_debug = Start
debug_again=Restart
stop=Stop
delete=Delete
start_use=Start use
more=More
gpu_type_all=All
model_download=Model Download
@@ -1128,6 +1129,8 @@ export_result_to_dataset = Export the results to a dataset
loader_result_file = Loading results file...

cloudbrain=Cloudbrain
superCompute=HPC
superComputeTask=HPC Task
cloudbrain.task = Cloudbrain Task
cloudbrain.search = Seach Task Name
cloudbrain.new=New cloudbrain
@@ -3182,6 +3185,7 @@ task_c2ent_mludebugjob=`created MLU type debugging task <a href="%s/grampus/trai
task_c2ent_mlutrainjob=`created MLU type train task <a href="%s/grampus/train-job/%s">%s</a>`
task_c2net_dcudebugjob=`created DCU type debugging task <a href="%s/grampus/notebook/%s">%s</a>`
task_c2ent_onlineinferjob=`created GPU type online inference task <a href="%s/grampus/onlineinfer/%s">%s</a>`
task_c2net_cpusupercomputejob=`created CPU type HPC task <a href="%s/supercompute/job/%s">%s</a>`
task_nputrainjob=`created NPU training task <a href="%s/modelarts/train-job/%s">%s</a>`
task_inferencejob=`created reasoning task <a href="%s/modelarts/inference-job/%s">%s</a>`
task_benchmark=`created profiling task <a href="%s/cloudbrain/benchmark/%s">%s</a>`
@@ -3352,6 +3356,7 @@ TRAIN = TRAIN
INFERENCE = INFERENCE
BENCHMARK = BENCHMARK
ONLINEINFERENCE = ONLINEINFERENCE
SUPERCOMPUTE = HPC
brain_area = Brain Area

Delete_failed=Fail to delete the job, please try again later.


+ 5
- 0
options/locale/locale_zh-CN.ini View File

@@ -1095,6 +1095,7 @@ online_debug = 在线推理
debug_again=再次调试
stop=停止
delete=删除
start_use=开始使用
more=更多
gpu_type_all=全部
model_download=结果下载
@@ -1127,6 +1128,8 @@ export_result_to_dataset = 导出结果至数据集
loader_result_file = 正在加载结果文件中...

cloudbrain=云脑
superCompute=超算
superComputeTask=超算任务
cloudbrain.task = 云脑任务
cloudbrain.search = 搜索任务名称
cloudbrain.new=新建任务
@@ -3200,6 +3203,7 @@ task_c2ent_mludebugjob=`创建了MLU类型调试任务 <a href="%s/grampus/noteb
task_c2ent_mlutrainjob=`创建了MLU类型训练任务 <a href="%s/grampus/train-job/%s">%s</a>`
task_c2net_dcudebugjob=`创建了DCU类型调试任务 <a href="%s/grampus/notebook/%s">%s</a>`
task_c2ent_onlineinferjob=`创建了GPU类型在线推理任务 <a href="%s/grampus/onlineinfer/%s">%s</a>`
task_c2net_cpusupercomputejob=`创建了CPU类型超算任务 <a href="%s/supercompute/job/%s">%s</a>`
task_nputrainjob=`创建了NPU类型训练任务 <a href="%s/modelarts/train-job/%s">%s</a>`
task_inferencejob=`创建了推理任务 <a href="%s/modelarts/inference-job/%s">%s</a>`
task_benchmark=`创建了评测任务 <a href="%s/cloudbrain/benchmark/%s">%s</a>`
@@ -3373,6 +3377,7 @@ TRAIN = 训练任务
INFERENCE = 推理任务
BENCHMARK = 评测任务
ONLINEINFERENCE = 在线推理
SUPERCOMPUTE = 超算任务
brain_area = 脑区

Delete_failed=任务删除失败,请稍后再试。


+ 6
- 1
public/home/home.js View File

@@ -253,7 +253,8 @@ document.onreadystatechange = function () {
html += " <span style=\"color: rgba(0,0,0,0.3)\">" + record.RefName + "</span>"
}
}
else if(record.OpType == "25" || record.OpType == "29" || record.OpType == "39" || record.OpType == "40" || record.OpType == "41" || record.OpType == "43"|| record.OpType == "44"|| record.OpType == "45"|| record.OpType == "46"){
else if(record.OpType == "25" || record.OpType == "29" || record.OpType == "39" || record.OpType == "40" || record.OpType == "41"
|| record.OpType == "43"|| record.OpType == "44"|| record.OpType == "45"|| record.OpType == "46"|| record.OpType == "47"){
html += recordPrefix + actionName;
const taskLink = getTaskLink(record);
if (taskLink) {
@@ -331,6 +332,8 @@ function getTaskLink(record){
} else {
re = '';
}
} else if(record.OpType == 47){
re = re + "/supercompute/job/" + record.Cloudbrain.ID;
} else if(record.OpType == 45){
re = re + "/grampus/onlineinfer/" + record.Content;
}
@@ -498,6 +501,7 @@ var actionNameZH={
"44":"创建了MLU类型训练任务",
"45":"创建了GPU类型在线推理任务",
"46":"创建了DCU类型调试任务",
"47":"创建了CPU类型超算任务",
};

var actionNameEN={
@@ -537,6 +541,7 @@ var actionNameEN={
"44":" created MLU type training task ",
"45":" created GPU type online inference task ",
"46":" created DCU type debugging task ",
"47":" created CPU type super compute task ",
};

var repoAndOrgZH={


BIN
public/img/supercompute/mmlspark.jpg View File

Before After
Width: 543  |  Height: 300  |  Size: 10 KiB

+ 3
- 2
routers/repo/cloudbrain.go View File

@@ -2039,6 +2039,7 @@ func SyncCloudbrainStatus() {
if task.Duration >= setting.MaxDuration && task.JobType == string(models.JobTypeDebug) {
ai_task.StopCloudbrain(task)
}

continue
}
if task.Type == models.TypeCloudBrainOne {
@@ -2065,7 +2066,7 @@ func SyncCloudbrainStatus() {
log.Error("task.JobType(%s) is error:%s", task.DisplayJobName, task.JobType)
}
} else if task.Type == models.TypeC2Net {
if task.JobType == string(models.JobTypeDebug) {
if task.JobType == string(models.JobTypeDebug) || task.JobType == string(models.JobTypeSuperCompute) {
cloudbrainTask.SyncGrampusNotebookStatus(task)
} else {
result, err := grampus.GetJob(task.JobID)
@@ -2110,7 +2111,7 @@ func SyncCloudbrainStatus() {
log.Error("task.Type(%s) is error:%d", task.JobName, task.Type)
}
if task.Status != string(models.JobWaiting) {
if task.Duration >= setting.MaxDuration && task.JobType == string(models.JobTypeDebug) {
if (task.Duration >= setting.MaxDuration && task.JobType == string(models.JobTypeDebug)) || (task.Duration >= setting.Grampus.MMLSparkMaxTime && task.JobType == string(models.JobTypeSuperCompute)) {
log.Info("begin to stop job(%s), because of the duration", task.DisplayJobName)
err = cloudbrainTask.StopDebugJob(task)
if err != nil {


+ 1
- 0
routers/repo/modelarts.go View File

@@ -811,6 +811,7 @@ func NotebookDel(ctx *context.Context) {

func TrainJobIndex(ctx *context.Context) {
MustEnableModelArts(ctx)
ctx.Data["PageIsCloudBrain"] = true
ctx.HTML(200, tplModelArtsTrainJobIndex)
/*
repo := ctx.Repo.Repository


+ 8
- 0
routers/routes/routes.go View File

@@ -12,6 +12,8 @@ import (
"text/template"
"time"

"code.gitea.io/gitea/routers/super_compute"

"code.gitea.io/gitea/routers/tech"

"code.gitea.io/gitea/routers/badge"
@@ -1303,6 +1305,12 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Post("/create", reqWechatBind, reqRepoCloudBrainWriter, bindIgnErr(auth.CreateCloudBrainInferencForm{}), context.PointAccount(), repo.CloudBrainInferenceJobCreate)
})
}, context.RepoRef())
m.Group("/supercompute", func() {
m.Get("", reqRepoCloudBrainReader, super_compute.GetAPPList)
m.Get("/job", reqRepoCloudBrainReader, super_compute.GetJobList)
m.Get("/job/create", reqRepoCloudBrainWriter, super_compute.CreateUI)
m.Get("/job/:id", reqRepoCloudBrainReader, super_compute.GetDetailUI)
})
m.Group("/grampus", func() {
m.Group("/notebook", func() {
m.Group("/:id", func() {


+ 33
- 0
routers/super_compute/super_compute.go View File

@@ -0,0 +1,33 @@
package super_compute

import (
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
)

const (
tplAPPList base.TplName = "repo/supercompute/index"
tplJobList base.TplName = "repo/supercompute/list"
tplCreateUI base.TplName = "repo/supercompute/create"
tplDetail base.TplName = "repo/supercompute/detail"
)

func GetAPPList(ctx *context.Context) {
ctx.Data["PageIsSuperCompute"] = true
ctx.HTML(200, tplAPPList)
}

func GetJobList(ctx *context.Context) {
ctx.Data["PageIsSuperCompute"] = true
ctx.HTML(200, tplJobList)
}

func CreateUI(ctx *context.Context) {
ctx.Data["PageIsSuperCompute"] = true
ctx.HTML(200, tplCreateUI)
}

func GetDetailUI(ctx *context.Context) {
ctx.Data["PageIsSuperCompute"] = true
ctx.HTML(200, tplDetail)
}

+ 5
- 1
services/ai_task_service/task/grampus_notebook_task.go View File

@@ -1,9 +1,10 @@
package task

import (
"code.gitea.io/gitea/entity"
"strings"

"code.gitea.io/gitea/entity"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
@@ -107,8 +108,11 @@ func GetGrampusNoteBookConfig(opts entity.AITaskConfigKey) *entity.AITaskBaseCon
config.ActionType = models.ActionCreateGrampusMLUDebugTask
case models.DCU:
config.ActionType = models.ActionCreateGrampusDCUDebugTask
case models.CPU:
config.ActionType = models.ActionCreateSuperComputeTask

}

config.IsActionUseJobId = false
config.DatasetsLimitSizeGB = setting.DebugAttachSize
config.DatasetsMaxNum = setting.MaxDatasetNum


+ 1
- 0
services/ai_task_service/task/opt_handler.go View File

@@ -419,6 +419,7 @@ func (DefaultCreationHandler) InsertCloudbrainRecord4Async(ctx *context.Creation
CreatedUnix: timeutil.TimeStampNow(),
UpdatedUnix: timeutil.TimeStampNow(),
GpuQueue: ctx.Spec.QueueCode,
AppName: req.AppName,
}

err := models.CreateCloudbrain(c)


+ 88
- 0
services/ai_task_service/task/super_compute_task.go View File

@@ -0,0 +1,88 @@
package task

import (
"strconv"
"time"

"code.gitea.io/gitea/entity"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/notification"
"code.gitea.io/gitea/routers/response"
"code.gitea.io/gitea/services/ai_task_service/context"
)

type SuperComputeTaskTemplate struct {
GrampusNoteBookTaskTemplate
}

func init() {
t := &SuperComputeTaskTemplate{
GrampusNoteBookTaskTemplate: GrampusNoteBookTaskTemplate{
DefaultAITaskTemplate: DefaultAITaskTemplate{
ClusterType: entity.C2Net,
JobType: models.JobTypeSuperCompute,
Config: GetGrampusNoteBookConfig,
},
},
}
RegisterTask(models.JobTypeSuperCompute, entity.C2Net, t)
}

func (g SuperComputeTaskTemplate) GetImages(computeSource models.ComputeSource) ([]entity.ClusterImage, bool, *response.BizError) {
c := g.GetMyCluster()
if c == nil {
log.Error("Get cluster failed")
return nil, false, response.SYSTEM_ERROR
}
l, f, err := c.GetNotebookImages(entity.GetImageReq{
ComputeSource: computeSource,
JobType: models.JobTypeDebug,
})
if err != nil {
log.Error("GetImages err.computeSource=%s err =%v", computeSource.Name, err)
return nil, false, response.NewBizError(err)
}
return l, f, nil
}

func (t SuperComputeTaskTemplate) Create(ctx *context.CreationContext) (*entity.CreateTaskRes, *response.BizError) {
c := &CreateOperator{}
err := c.Next(t.CheckParamFormat).
Next(t.CheckMultiRequest).
Next(t.CheckDisplayJobName).
Next(t.LoadSpec).
Next(t.CheckPointBalance).
Next(t.CheckDatasets).
Next(t.CheckBranchExists).
Next(t.CheckModel).
Next(t.InsertCloudbrainRecord4Async).
AsyncNextWithErrFun(t.BuildContainerData, t.CallCreationAPI, t.AfterCallCreationAPI4Async, t.NotifyCreation, t.HandleErr4Async).
Operate(ctx)
if err != nil {
log.Error("create GrampusNoteBookTask err.%v", err)
return nil, err
}
return &entity.CreateTaskRes{ID: ctx.NewCloudbrain.ID}, nil
}

func (SuperComputeTaskTemplate) NotifyCreation(ctx *context.CreationContext) *response.BizError {
req := ctx.Request

var actionType = models.ActionCreateSuperComputeTask

task, err := models.GetCloudbrainByCloudbrainID(ctx.NewCloudbrain.ID)
if err != nil {
log.Error("GetCloudbrainByJobID failed: %v", err.Error())
return response.NewBizError(err)
}
stringId := strconv.FormatInt(task.ID, 10)
notification.NotifyOtherTask(ctx.User, ctx.Repository, stringId, req.DisplayJobName, actionType)
return nil
}

func (g SuperComputeTaskTemplate) GetDisplayJobName(userName string) string {
t := time.Now()
millisecondStr := strconv.FormatInt((t.UnixNano()%1e6/1e3)%1000, 10)
return "mmlspark-" + t.Format("20060102150405") + millisecondStr
}

+ 9
- 2
services/ai_task_service/task/task_base.go View File

@@ -1,6 +1,11 @@
package task

import (
"errors"
"time"

cloudbrainService "code.gitea.io/gitea/services/cloudbrain"

"code.gitea.io/gitea/entity"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/convert"
@@ -16,9 +21,7 @@ import (
"code.gitea.io/gitea/services/ai_task_service/container_builder"
"code.gitea.io/gitea/services/ai_task_service/context"
"code.gitea.io/gitea/services/cloudbrain/resource"
"errors"
"strconv"
"time"
)

var taskMap = map[string]AITaskTemplate{}
@@ -62,6 +65,7 @@ type AITaskTemplate interface {
GetConfig(opts entity.AITaskConfigKey) *entity.AITaskBaseConfig
GetNodeInfo(cloudbrainId int64) ([]entity.AITaskNodeInfo, *response.BizError)
GetAllowedWorkerNum(userId int64, computeSource *models.ComputeSource) ([]int, *response.BizError)
GetDisplayJobName(userName string) string
}

type GetConfigFunc func(entity.AITaskConfigKey) *entity.AITaskBaseConfig
@@ -519,3 +523,6 @@ func isInNodes(nodes []int, num int) bool {
return false

}
func (g DefaultAITaskTemplate) GetDisplayJobName(userName string) string {
return cloudbrainService.GetDisplayJobName(userName)
}

+ 5
- 3
services/ai_task_service/task/task_creation_info.go View File

@@ -7,7 +7,6 @@ import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/routers/response"
cloudbrainService "code.gitea.io/gitea/services/cloudbrain"
"code.gitea.io/gitea/services/cloudbrain/cloudbrainTask"
"code.gitea.io/gitea/services/reward/point/account"
)
@@ -45,13 +44,16 @@ func GetAITaskCreationInfo(req entity.GetAITaskCreationInfoReq) (*entity.Creatio
}
//积分开关
result.PaySwitch = setting.CloudBrainPaySwitch
//生成任务名称
result.DisplayJobName = cloudbrainService.GetDisplayJobName(req.User.Name)

t, err := GetAITaskTemplate(req.JobType, req.ClusterType)

if err != nil {
log.Error("param error")
return nil, err
}

//生成任务名称
result.DisplayJobName = t.GetDisplayJobName(req.User.Name)
// 查询镜像列表
if images, canUseAll, err := t.GetImages(*req.ComputeSource); err == nil {
result.Images = images


+ 1
- 0
services/ai_task_service/task/task_service.go View File

@@ -133,6 +133,7 @@ func buildAITaskInfo(task *models.Cloudbrain, creator *models.User, config *enti
CreatorName: creator.GetDisplayName(),
EngineName: task.EngineName,
UserId: task.UserID,
AppName: task.AppName,
}, nil
}



+ 1
- 1
services/socketwrap/clientManager.go View File

@@ -10,7 +10,7 @@ import (
"github.com/elliotchance/orderedmap"
)

var opTypes = []int{1, 2, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 17, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 39, 40, 41, 42, 43, 44, 45, 46}
var opTypes = []int{1, 2, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 17, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 39, 40, 41, 42, 43, 44, 45, 46, 47}

type ClientsManager struct {
Clients *orderedmap.OrderedMap


+ 24
- 4
templates/admin/cloudbrain/list.tmpl View File

@@ -89,7 +89,7 @@
<div class="row">
<!-- 任务名 -->
{{$JobID := '0'}}
{{if eq .JobType "DEBUG" "TRAIN" "SNN4IMAGENET" "BRAINSCORE" "BENCHMARK" "MODELSAFETY" "SNN4ECOSET" "SIM2BRAIN_SNN" "ONLINEINFERENCE"}}
{{if eq .JobType "DEBUG" "TRAIN" "SUPERCOMPUTE" "SNN4IMAGENET" "BRAINSCORE" "BENCHMARK" "MODELSAFETY" "SNN4ECOSET" "SIM2BRAIN_SNN" "ONLINEINFERENCE"}}
{{$JobID = .Cloudbrain.ID}}
{{else}}
{{$JobID = .JobID}}
@@ -103,6 +103,13 @@
<span class="fitted"
style="width: 90%;vertical-align: middle;">{{.DisplayJobName}}</span>
</a>
{{else if eq .JobType "SUPERCOMPUTE"}}
<a class="title"
href="{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}/supercompute/job/{{$JobID}}"
title="{{.DisplayJobName}}" style="font-size: 14px;padding-right:0px">
<span class="fitted"
style="width: 90%;vertical-align: middle;">{{.DisplayJobName}}</span>
</a>
{{else if or (eq .JobType "SNN4IMAGENET") (eq .JobType "BRAINSCORE") (eq .JobType "SNN4ECOSET") (eq .JobType "SIM2BRAIN_SNN")}}
<a class="title"
href="{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}/cloudbrain/benchmark/{{$JobID}}"
@@ -148,7 +155,7 @@
<div class="two wide column text center nowrap"
style="width: 6% !important;">
<span class="job-status" id="{{$JobID}}"
data-repopath='{{.Repo.OwnerName}}/{{.Repo.Name}}{{if eq .JobType "DEBUG" "ONLINEINFERENCE"}}{{if eq .Cloudbrain.Type 2}}/grampus/notebook{{else}}{{if eq .ComputeResource "CPU/GPU"}}/cloudbrain{{else}}/modelarts/notebook{{end}}{{end}}{{else if eq .JobType "INFERENCE"}}/modelarts/inference-job{{else if eq .JobType "TRAIN"}}/modelarts/train-job{{else if eq .JobType "BENCHMARK" "MODELSAFETY"}}/cloudbrain{{end}}'
data-repopath='{{.Repo.OwnerName}}/{{.Repo.Name}}{{if eq .JobType "DEBUG" "ONLINEINFERENCE" "SUPERCOMPUTE"}}{{if eq .Cloudbrain.Type 2}}/grampus/notebook{{else}}{{if eq .ComputeResource "CPU/GPU"}}/cloudbrain{{else}}/modelarts/notebook{{end}}{{end}}{{else if eq .JobType "INFERENCE"}}/modelarts/inference-job{{else if eq .JobType "TRAIN"}}/modelarts/train-job{{else if eq .JobType "BENCHMARK" "MODELSAFETY"}}/cloudbrain{{end}}'
data-jobid="{{$JobID}}" data-version="{{.VersionName}}"
data-cloudbrainid="{{.Cloudbrain.ID}}">
<span><i id="{{$JobID}}-icon" style="vertical-align: middle;"
@@ -270,6 +277,19 @@
</a>
</form>
</div>
{{end}}
{{if eq .JobType "SUPERCOMPUTE"}}
<div class="ui compact buttons">
<form id="debugAgainForm-{{$JobID}}">
{{$.CsrfTokenHtml}}
<a id="ai-debug-infer-{{$JobID}}"
class='ui basic ai_debug {{if eq .Status "RUNNING"}} blue {{else}} disabled {{end}}button'
data-jobid="{{$JobID}}"
data-repopath='{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}{{if eq .Cloudbrain.Type 2}}/grampus/notebook{{else}}{{if eq .ComputeResource "CPU/GPU"}}/cloudbrain{{else}}/modelarts/notebook{{end}}{{end}}/{{$JobID}}/'>
{{$.i18n.Tr "repo.start_use"}}
</a>
</form>
</div>
{{end}}
<!-- 停止任务 -->
<div class="ui compact buttons">
@@ -284,7 +304,7 @@
</a>
</form>
{{else}}
{{if eq .JobType "DEBUG" "BENCHMARK" "SNN4IMAGENET" "BRAINSCORE" "SNN4ECOSET" "SIM2BRAIN_SNN" "ONLINEINFERENCE"}}
{{if eq .JobType "DEBUG" "SUPERCOMPUTE" "BENCHMARK" "SNN4IMAGENET" "BRAINSCORE" "SNN4ECOSET" "SIM2BRAIN_SNN" "ONLINEINFERENCE"}}
<form id="stopForm-{{$JobID}}" style="margin-left:-1px;">
{{$.CsrfTokenHtml}}
<a style="padding: 0.5rem 1rem;" id="ai-stop-{{$JobID}}"
@@ -329,7 +349,7 @@
</form>
{{else}}
<form class="ui compact buttons" id="delForm-{{$JobID}}"
action='{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}{{if eq .JobType "BENCHMARK"}}/cloudbrain/benchmark{{else if or (eq .JobType "SNN4IMAGENET") (eq .JobType "BRAINSCORE") (eq .JobType "SNN4ECOSET") (eq .JobType "SIM2BRAIN_SNN")}}/cloudbrain{{else if eq .JobType "DEBUG" "ONLINEINFERENCE"}}{{if eq .Cloudbrain.Type 2}}/grampus/notebook{{else}}{{if eq .ComputeResource "CPU/GPU"}}/cloudbrain{{else}}/modelarts/notebook{{end}}{{end}}{{else if eq .JobType "TRAIN"}}{{if eq .Cloudbrain.Type 1}}/modelarts/train-job{{else if eq .Cloudbrain.Type 0}}/cloudbrain/train-job{{else if eq .Cloudbrain.Type 2}}/grampus/train-job{{end}}{{else if eq .JobType "INFERENCE"}}{{if eq .Cloudbrain.Type 0}}/cloudbrain/train-job{{end}}{{end}}/{{$JobID}}/del?isadminpage=true'
action='{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}{{if eq .JobType "BENCHMARK"}}/cloudbrain/benchmark{{else if or (eq .JobType "SNN4IMAGENET") (eq .JobType "BRAINSCORE") (eq .JobType "SNN4ECOSET") (eq .JobType "SIM2BRAIN_SNN")}}/cloudbrain{{else if eq .JobType "DEBUG" "ONLINEINFERENCE" "SUPERCOMPUTE"}}{{if eq .Cloudbrain.Type 2}}/grampus/notebook{{else}}{{if eq .ComputeResource "CPU/GPU"}}/cloudbrain{{else}}/modelarts/notebook{{end}}{{end}}{{else if eq .JobType "TRAIN"}}{{if eq .Cloudbrain.Type 1}}/modelarts/train-job{{else if eq .Cloudbrain.Type 0}}/cloudbrain/train-job{{else if eq .Cloudbrain.Type 2}}/grampus/train-job{{end}}{{else if eq .JobType "INFERENCE"}}{{if eq .Cloudbrain.Type 0}}/cloudbrain/train-job{{end}}{{end}}/{{$JobID}}/del?isadminpage=true'
method="post">
{{$.CsrfTokenHtml}}
<input type="hidden" value="{{.Cloudbrain.ID}}" style="display:none" name="id" />


+ 3
- 1
templates/admin/cloudbrain/search.tmpl View File

@@ -38,6 +38,7 @@
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=MODELSAFETY&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="MODELSAFETY">MODELSAFETY</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=SNN4ECOSET&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="SNN4ECOSET">SNN4ECOSET</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=SIM2BRAIN_SNN&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="SIM2BRAIN_SNN">SIM2BRAIN_SNN</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=SUPERCOMPUTE&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="SUPERCOMPUTE">SUPERCOMPUTE</a>
</div>
</div>
<div class="ui selection dropdown" style="min-width: 10em;min-height:2.6em;border-radius: .28571429rem;margin-right: 1em;padding: .67em 3.2em .7em 1em;">
@@ -50,6 +51,7 @@
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType=GCU&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="GCU">GCU</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType=MLU&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="MLU">MLU</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType=DCU&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="DCU">DCU</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType=CPU&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="CPU">CPU</a>
</div>
</div>
<div class="ui selection dropdown" style="min-width: 10em;min-height:2.6em;border-radius: .28571429rem;margin-right: 1em;padding: .67em 3.2em .7em 1em;">
@@ -91,7 +93,7 @@
for (var i = 0, iLen = data.length; i < iLen; i++) {
var dataI = data[i];
var aiCenterCode = dataI.AiCenterCode;
var aiCenterName = dataI.AiCenterName;
var aiCenterName = dataI.AiCenterName || dataI.AiCenterCode;
var itemClone = itemEl.clone();
var oHref = itemClone.attr('href');
var oId = itemClone.attr('id');


+ 4
- 2
templates/admin/cloudbrain/search_dashboard.tmpl View File

@@ -48,7 +48,8 @@
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=BENCHMARK&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="BENCHMARK">{{.i18n.Tr "cloudbrain.BENCHMARK"}}</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=ONLINEINFERENCE&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="ONLINEINFERENCE">{{.i18n.Tr "cloudbrain.ONLINEINFERENCE"}}</a>
<!-- <a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=SNN4IMAGENET&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="BENCHMARK">{{.i18n.Tr "cloudbrain.SNN4IMAGENET"}}</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=BRAINSCORE&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="BENCHMARK">{{.i18n.Tr "cloudbrain.BRAINSCORE"}}</a> -->
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=BRAINSCORE&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="BENCHMARK">{{.i18n.Tr "cloudbrain.BRAINSCORE"}}</a> -->
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=SUPERCOMPUTE&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="SUPERCOMPUTE">{{.i18n.Tr "repo.superComputeTask"}}</a>
</div>
</div>
<div class="ui selection dropdown" style="min-width: 10em;min-height:2.6em;border-radius: .28571429rem;margin-right: 1em;padding: .67em 3.2em .7em 1em;">
@@ -61,6 +62,7 @@
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType=GCU&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="GCU">GCU</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType=MLU&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="MLU">MLU</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType=DCU&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="DCU">DCU</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType=CPU&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="CPU">CPU</a>
</div>
</div>
<div class="ui selection dropdown" style="min-width: 10em;min-height:2.6em;border-radius: .28571429rem;margin-right: 1em;padding: .67em 3.2em .7em 1em;">
@@ -105,7 +107,7 @@
for (var i = 0, iLen = data.length; i < iLen; i++) {
var dataI = data[i];
var aiCenterCode = dataI.AiCenterCode;
var aiCenterName = dataI.AiCenterName;
var aiCenterName = dataI.AiCenterName || dataI.AiCenterCode;
var itemClone = itemEl.clone();
var oHref = itemClone.attr('href');
var oId = itemClone.attr('id');


+ 9
- 1
templates/repo/header.tmpl View File

@@ -201,7 +201,15 @@
</span>
</a>
{{end}}
<!-- {{if .IsSigned}}
{{if .Permission.CanRead $.UnitTypeCloudBrain}}
<a class="{{if .PageIsSuperCompute}}active{{end}} item" href="{{.RepoLink}}/supercompute">
<span>
<svg class="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16"><path d="M14 18V20L16 21V22H8L7.99639 21.0036L10 20V18H2.9918C2.44405 18 2 17.5511 2 16.9925V4.00748C2 3.45107 2.45531 3 2.9918 3H21.0082C21.556 3 22 3.44892 22 4.00748V16.9925C22 17.5489 21.5447 18 21.0082 18H14ZM4 5V14H20V5H4Z"></path></svg>
{{.i18n.Tr "repo.superCompute"}}
</span>
</a>
{{end}}
<!-- {{if .IsSigned}}
<a class="{{if .PageIsBlockChain}}active{{end}} item " href="{{.RepoLink}}/blockchain">
{{svg "octicon-law" 16}}
{{.i18n.Tr "repo.balance"}}


+ 8
- 0
templates/repo/supercompute/create.tmpl View File

@@ -0,0 +1,8 @@
{{template "base/head" .}}
<link rel="stylesheet" href="{{StaticUrlPrefix}}/css/vp-cloudbrain-super-create.css?v={{MD5 AppVer}}" />
<div class="repository release dataset-list view">
{{template "repo/header" .}}
<div id="__vue-root"></div>
</div>
<script src="{{StaticUrlPrefix}}/js/vp-cloudbrain-super-create.js?v={{MD5 AppVer}}"></script>
{{template "base/footer" .}}

+ 8
- 0
templates/repo/supercompute/detail.tmpl View File

@@ -0,0 +1,8 @@
{{template "base/head" .}}
<link rel="stylesheet" href="{{StaticUrlPrefix}}/css/vp-cloudbrain-super-detail.css?v={{MD5 AppVer}}" />
<div class="repository release dataset-list view">
{{template "repo/header" .}}
<div id="__vue-root"></div>
</div>
<script src="{{StaticUrlPrefix}}/js/vp-cloudbrain-super-detail.js?v={{MD5 AppVer}}"></script>
{{template "base/footer" .}}

+ 8
- 0
templates/repo/supercompute/index.tmpl View File

@@ -0,0 +1,8 @@
{{template "base/head" .}}
<link rel="stylesheet" href="{{StaticUrlPrefix}}/css/vp-cloudbrain-super-apps.css?v={{MD5 AppVer}}" />
<div class="repository release dataset-list view">
{{template "repo/header" .}}
<div id="__vue-root"></div>
</div>
<script src="{{StaticUrlPrefix}}/js/vp-cloudbrain-super-apps.js?v={{MD5 AppVer}}"></script>
{{template "base/footer" .}}

+ 8
- 0
templates/repo/supercompute/list.tmpl View File

@@ -0,0 +1,8 @@
{{template "base/head" .}}
<link rel="stylesheet" href="{{StaticUrlPrefix}}/css/vp-cloudbrain-super-list.css?v={{MD5 AppVer}}" />
<div class="repository release dataset-list view">
{{template "repo/header" .}}
<div id="__vue-root"></div>
</div>
<script src="{{StaticUrlPrefix}}/js/vp-cloudbrain-super-list.js?v={{MD5 AppVer}}"></script>
{{template "base/footer" .}}

+ 25
- 4
templates/user/dashboard/cloudbrains.tmpl View File

@@ -7,6 +7,7 @@
data-debug-again="{{$.i18n.Tr "repo.debug_again"}}" data-debug-task="{{$.i18n.Tr "cloudbrain.DEBUG"}}"
data-train-task="{{$.i18n.Tr "cloudbrain.TRAIN"}}" data-inference-task="{{$.i18n.Tr "cloudbrain.INFERENCE"}}"
data-benchmark-task="{{$.i18n.Tr "cloudbrain.BENCHMARK"}}" data-inferonline-task="{{$.i18n.Tr "cloudbrain.ONLINEINFERENCE"}}"
data-supercompute-task="{{$.i18n.Tr "repo.superComputeTask"}}"
data-all-cluster="{{.i18n.Tr "cloudbrain.all_resource_cluster"}}"
data-all-aiCenter="{{.i18n.Tr "cloudbrain.all_ai_center"}}"
data-cluster-c2net="{{.i18n.Tr "cloudbrain.resource_cluster_c2net"}}"
@@ -71,7 +72,7 @@
<div class="row">
<!-- 任务名 -->
{{$JobID := '0'}}
{{if eq .JobType "DEBUG" "TRAIN" "SNN4IMAGENET" "BRAINSCORE" "BENCHMARK" "MODELSAFETY" "SNN4ECOSET" "SIM2BRAIN_SNN" "ONLINEINFERENCE"}}
{{if eq .JobType "DEBUG" "TRAIN" "SUPERCOMPUTE" "SNN4IMAGENET" "BRAINSCORE" "BENCHMARK" "MODELSAFETY" "SNN4ECOSET" "SIM2BRAIN_SNN" "ONLINEINFERENCE"}}
{{$JobID = .Cloudbrain.ID}}
{{else}}
{{$JobID = .JobID}}
@@ -85,6 +86,13 @@
<span class="fitted"
style="width: 90%;vertical-align: middle;">{{.DisplayJobName}}</span>
</a>
{{else if eq .JobType "SUPERCOMPUTE"}}
<a class="title"
href="{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}/supercompute/job/{{$JobID}}"
title="{{.DisplayJobName}}" style="font-size: 14px;padding-right:0px">
<span class="fitted"
style="width: 90%;vertical-align: middle;">{{.DisplayJobName}}</span>
</a>
{{else if (eq .JobType "SNN4IMAGENET" "BRAINSCORE" "SNN4ECOSET" "SIM2BRAIN_SNN")}}
<a class="title"
href="{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}/cloudbrain/benchmark/{{$JobID}}"
@@ -130,7 +138,7 @@
<div class="two wide column text center nowrap"
style="width: 8% !important;">
<span class="job-status" id="{{$JobID}}"
data-repopath='{{.Repo.OwnerName}}/{{.Repo.Name}}{{if eq .JobType "DEBUG" "ONLINEINFERENCE"}}{{if eq .Cloudbrain.Type 2}}/grampus/notebook{{else}}{{if eq .ComputeResource "CPU/GPU"}}/cloudbrain{{else}}/modelarts/notebook{{end}}{{end}}{{else if eq .JobType "INFERENCE"}}{{if eq .ComputeResource "CPU/GPU"}}/cloudbrain{{else}}/modelarts{{end}}/inference-job{{else if eq .JobType "TRAIN"}}{{if eq .ComputeResource "NPU"}}/modelarts/train-job{{else}}/cloudbrain/train-job{{end}}{{else if eq .JobType "BENCHMARK" "MODELSAFETY"}}/cloudbrain{{end}}'
data-repopath='{{.Repo.OwnerName}}/{{.Repo.Name}}{{if eq .JobType "DEBUG" "ONLINEINFERENCE" "SUPERCOMPUTE"}}{{if eq .Cloudbrain.Type 2}}/grampus/notebook{{else}}{{if eq .ComputeResource "CPU/GPU"}}/cloudbrain{{else}}/modelarts/notebook{{end}}{{end}}{{else if eq .JobType "INFERENCE"}}{{if eq .ComputeResource "CPU/GPU"}}/cloudbrain{{else}}/modelarts{{end}}/inference-job{{else if eq .JobType "TRAIN"}}{{if eq .ComputeResource "NPU"}}/modelarts/train-job{{else}}/cloudbrain/train-job{{end}}{{else if eq .JobType "BENCHMARK" "MODELSAFETY"}}/cloudbrain{{end}}'
data-jobid="{{$JobID}}" data-version="{{.VersionName}}"
data-cloudbrainid="{{.Cloudbrain.ID}}"
data-bootfile="{{.BootFile}}">
@@ -232,6 +240,19 @@
</form>
</div>
{{end}}
{{if eq .JobType "SUPERCOMPUTE"}}
<div class="ui compact buttons">
<form id="debugAgainForm-{{$JobID}}">
{{$.CsrfTokenHtml}}
<a id="ai-debug-infer-{{$JobID}}"
class='ui basic ai_debug {{if eq .Status "RUNNING"}} blue {{else}} disabled {{end}}button'
data-jobid="{{$JobID}}"
data-repopath='{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}{{if eq .Cloudbrain.Type 2}}/grampus/notebook{{else}}{{if eq .ComputeResource "CPU/GPU"}}/cloudbrain{{else}}/modelarts/notebook{{end}}{{end}}/{{$JobID}}/'>
{{$.i18n.Tr "repo.start_use"}}
</a>
</form>
</div>
{{end}}
<!-- 停止任务 -->
<div class="ui compact buttons">
{{if eq .JobType "MODELSAFETY"}}
@@ -245,7 +266,7 @@
</a>
</form>
{{else}}
{{if eq .JobType "DEBUG" "BENCHMARK" "SNN4IMAGENET" "BRAINSCORE" "SNN4ECOSET" "SIM2BRAIN_SNN" "ONLINEINFERENCE"}}
{{if eq .JobType "DEBUG" "SUPERCOMPUTE" "BENCHMARK" "SNN4IMAGENET" "BRAINSCORE" "SNN4ECOSET" "SIM2BRAIN_SNN" "ONLINEINFERENCE"}}
<form id="stopForm-{{$JobID}}" style="margin-left:-1px;">
{{$.CsrfTokenHtml}}
<a style="padding: 0.5rem 1rem;" id="ai-stop-{{$JobID}}"
@@ -298,7 +319,7 @@
</form>
{{else}}
<form class="ui compact buttons" id="delForm-{{$JobID}}"
action='{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}{{if eq .JobType "BENCHMARK"}}/cloudbrain/benchmark{{else if or (eq .JobType "SNN4IMAGENET") (eq .JobType "BRAINSCORE") (eq .JobType "SNN4ECOSET") (eq .JobType "SIM2BRAIN_SNN")}}/cloudbrain{{else if eq .JobType "DEBUG" "ONLINEINFERENCE"}}{{if eq .Cloudbrain.Type 2}}/grampus/notebook{{else}}{{if eq .ComputeResource "CPU/GPU"}}/cloudbrain{{else}}/modelarts/notebook{{end}}{{end}}{{else if eq .JobType "TRAIN"}}{{if eq .Cloudbrain.Type 1}}/modelarts/train-job{{else if eq .Cloudbrain.Type 0}}/cloudbrain/train-job{{else if eq .Cloudbrain.Type 2}}/grampus/train-job{{end}}{{else if eq .JobType "INFERENCE"}}{{if eq .Cloudbrain.Type 0}}/cloudbrain/train-job{{end}}{{end}}/{{$JobID}}/del?ishomepage=true'
action='{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}{{if eq .JobType "BENCHMARK"}}/cloudbrain/benchmark{{else if or (eq .JobType "SNN4IMAGENET") (eq .JobType "BRAINSCORE") (eq .JobType "SNN4ECOSET") (eq .JobType "SIM2BRAIN_SNN")}}/cloudbrain{{else if eq .JobType "DEBUG" "ONLINEINFERENCE" "SUPERCOMPUTE"}}{{if eq .Cloudbrain.Type 2}}/grampus/notebook{{else}}{{if eq .ComputeResource "CPU/GPU"}}/cloudbrain{{else}}/modelarts/notebook{{end}}{{end}}{{else if eq .JobType "TRAIN"}}{{if eq .Cloudbrain.Type 1}}/modelarts/train-job{{else if eq .Cloudbrain.Type 0}}/cloudbrain/train-job{{else if eq .Cloudbrain.Type 2}}/grampus/train-job{{end}}{{else if eq .JobType "INFERENCE"}}{{if eq .Cloudbrain.Type 0}}/cloudbrain/train-job{{end}}{{end}}/{{$JobID}}/del?ishomepage=true'
method="post">
{{$.CsrfTokenHtml}}
<input type="hidden" value="{{.Cloudbrain.ID}}" style="display:none" name="id" />


+ 9
- 1
templates/user/dashboard/feeds.tmpl View File

@@ -151,7 +151,13 @@
{{$.i18n.Tr "action.task_c2net_dcudebugjob" .GetRepoLink (Printf "%d" .Cloudbrain.ID) .RefName | Str2html}}
{{else}}
{{$.i18n.Tr "action.task_c2net_dcudebugjob" "" "" "" | Str2html}}<span style="">{{.RefName}}{{$.i18n.Tr "repo.issues.deleted_milestone"}}</span>
{{end}}
{{end}}
{{else if eq .GetOpType 47}}
{{if .Cloudbrain}}
{{$.i18n.Tr "action.task_c2net_cpusupercomputejob" .GetRepoLink (Printf "%d" .Cloudbrain.ID) .RefName | Str2html}}
{{else}}
{{$.i18n.Tr "action.task_c2net_cpusupercomputejob" "" "" "" | Str2html}}<span style="">{{.RefName}}{{$.i18n.Tr "repo.issues.deleted_milestone"}}</span>
{{end}}
{{else if eq .GetOpType 44}}
{{if .Cloudbrain}}
{{$.i18n.Tr "action.task_c2ent_mlutrainjob" .GetRepoLink (Printf "%d" .Cloudbrain.ID) .RefName | Str2html}}
@@ -213,6 +219,8 @@
<span class="text grey"><i class="ri-voice-recognition-line icon big"></i></span>
{{else if eq .GetOpType 46}}
<span class="text grey"><i class="ri-voice-recognition-line icon big"></i></span>
{{else if eq .GetOpType 47}}
<span class="text grey"><i class="ri-voice-recognition-line icon big"></i></span>
{{else if eq .GetOpType 27}}
<span class="text grey"><i class="ri-character-recognition-line icon big"></i></span>
{{else if eq .GetOpType 28}}


+ 2
- 0
web_src/js/features/cloudrbanin.js View File

@@ -551,6 +551,8 @@ function userSearchControll() {
jobType = $(".cloudbrain_debug").data("inference-task");
} else if (params.get("jobType") === "ONLINEINFERENCE") {
jobType = $(".cloudbrain_debug").data("inferonline-task");
} else if (params.get("jobType") === "SUPERCOMPUTE") {
jobType = $(".cloudbrain_debug").data("supercompute-task");
} else {
jobType = $(".cloudbrain_debug").data("benchmark-task");
}


+ 1
- 0
web_src/vuepages/apis/modules/cloudbrain.js View File

@@ -10,6 +10,7 @@ export const getAiTaskPrepareInfo = (params) => {
job_type: params.jobType,
compute_source: params.computeSource,
cluster_type: params.clusterType,
app_name: params.appName,
},
});
}


+ 11
- 5
web_src/vuepages/components/cloudbrain/TaskName.vue View File

@@ -4,9 +4,10 @@
<span :class="required ? 'required' : ''">{{ $t('cloudbrainObj.taskName') }}</span>
</div>
<div class="content" :class="errStatus ? 'error' : ''">
<el-input class="field-input" v-model="currentValue" @input="handleInput" @change="handleInputChange" maxlength="36"
:placeholder="$t('cloudbrainObj.taskName')" :autofocus="autofocus" :disabled="disabled"></el-input>
<div class="tips">{{ $t('cloudbrainObj.taskNameTips') }}</div>
<el-input class="field-input" v-model="currentValue" @input="handleInput" @change="handleInputChange" :maxlength="type == 'supercompute' ? 26 : 36"
:placeholder="$t('cloudbrainObj.taskName')" :autofocus="autofocus"></el-input>
<div v-if="type === 'supercompute'" class="tips">{{ $t('cloudbrainObj.taskNameTips1') }}</div>
<div v-else class="tips">{{ $t('cloudbrainObj.taskNameTips') }}</div>
</div>
</div>
</template>
@@ -21,8 +22,8 @@ export default {
userName: { type: String, required: true },
autofocus: { type: Boolean, default: true, },
generate: { type: Boolean, default: false, },
disabled: { type: Boolean, default: false },
required: { type: Boolean, default: true },
type: { type: String, default: '' },
},
data() {
return {
@@ -42,7 +43,12 @@ export default {
methods: {
check() {
const reg = /^[a-z0-9][a-z0-9\-_]{1,34}[a-z0-9\-]$/;
this.errStatus = !reg.test(this.currentValue);
const reg1 = /^[a-z][a-z0-9\-]{4,25}$/;
if (this.type == 'supercompute') {
this.errStatus = !reg1.test(this.currentValue);
} else {
this.errStatus = !reg.test(this.currentValue);
}
if (!this.required && this.currentValue == '') {
this.errStatus = false;
}


+ 6
- 0
web_src/vuepages/components/cloudbrain/details/ConfigInfo.vue View File

@@ -118,6 +118,9 @@ export default {
case 'taskName':
result = i18n.t('cloudbrainObj.taskName');
break;
case 'appName':
result = i18n.t('cloudbrainObj.appName');
break;
case 'spec':
result = i18n.t('cloudbrainObj.resourceSpec');
break;
@@ -211,6 +214,9 @@ export default {
case 'taskName':
result = task.display_job_name;
break;
case 'appName':
result = task.app_name;
break;
case 'imagev1':
result = `<span class="ui poping up clipboard"
id="clipboard-${SparkMD5.hash(task.image_url || task.image_name)}"


+ 2
- 2
web_src/vuepages/const/index.js View File

@@ -6,12 +6,12 @@ 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') },
];
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') }];
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: 'SUPERCOMPUTE', 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: 'GPU', v: 'GPU' }, { k: 'NPU', v: 'NPU' }, { k: 'GCU', v: 'GCU' }, { k: 'MLU', v: 'MLU' }, { k: 'DCU', v: 'DCU' }];
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' }];
export const ACC_CARD_TYPE = [{ k: 'T4', v: 'T4' }, { k: 'A100', v: 'A100' }, { k: 'V100', v: 'V100' }, { k: 'ASCEND910', v: 'Ascend 910' }, { k: 'MLU270', v: 'MLU270' }, { k: 'MLU290', v: 'MLU290' }, { k: 'RTX3080', v: 'RTX3080' }, { k: 'ENFLAME-T20', v: 'ENFLAME-T20' }, { k: 'DCU', v: 'DCU' }];
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') }];



+ 12
- 1
web_src/vuepages/langs/config/en-US.js View File

@@ -41,6 +41,7 @@ const en = {
inferenceTask: 'Inference Task',
benchmarkTask: 'Benchmark Task',
onlineinfer: "Online Inference",
superComputeTask: "HPC Task",
createPublicProject: 'Create Public Projects',
dailyPutforwardTasks: 'Daily Put Forward Tasks',
dailyPR: 'Daily PR',
@@ -511,7 +512,7 @@ const en = {
openi: 'OpenI Resource Cluster',
c2net: 'China Computing NET(Beta)',
create: 'New ',
createTask: 'New cloudbrain',
createTask: 'Create Task',
cluster: 'Resource cluster',
computeResource: 'Computing resources',
sameTaskTips1: 'You have created an <span>equivalent task</span> that is waiting or running, please wait for the task to finish before creating it.',
@@ -529,8 +530,13 @@ const en = {
taskPrepareTips: 'The task is currently being prepared. Drink a glass of water and come back to take a look~',
waitCountStart: 'Your current queue position is ',
waitCountEnd: '',
task: ' Task',
taskList: 'Task List',
taskName: 'Task name',
appName: 'App name',
appList: 'App List',
taskNameTips: 'Name must start with a lowercase letter or number,can include lowercase letter,number,_ and -,can not end with _, and can be up to 36 characters long.',
taskNameTips1: 'Name must start with a lowercase letter,can include lowercase letter,number,and -, and between 5 and 26 characters.',
taskDescr: 'Description',
taskDescrPlaceholder: 'The description should not exceed 255 characters',
codeBranch: 'Code branch',
@@ -568,6 +574,7 @@ const en = {
stop: 'Stop',
modify: 'Modify',
delete: 'Delete',
startUse: 'Start use',
more: 'More',
commitImage: 'Submit Image',
downloadModel: 'Download',
@@ -601,6 +608,7 @@ const en = {
debugTaskEmptyTip3: 'Instructions for use: You can refer to the OpenI AI collaboration platform<a href="{url}"> Help Center </a>.',
onlineInferTaskEmptyTitle: 'Online Inference task has not been created',
onlineInferEmptyTip2: 'Dataset: Cloud Brain 1 provides CPU/GPU,Cloud Brain 2 provides Ascend NPU.And dataset also needs to be uploaded to the corresponding environment;',
superTaskEmptyTitle: 'Super compute task has not been created',
deleteConfirmTips: 'Are you sure you want to delete this task? Once this task is deleted, it cannot be recovered.',
deletingTips: 'Task deletion in progress, please wait',
tabTitDebug: 'Debug Task',
@@ -644,6 +652,9 @@ const en = {


},
superComputeObj: {
mmlSparkDescr: `The full name of MMLSpark is Microsoft Machine Learning for Apache Spark, which supports users to run self-made container images and grants them root privileges within the container. Users can directly use Microsoft's MMLSpark provided by the platform.\nNote: MMLSpark is a Spark version provided by Microsoft for machine learning environments( <a target="_blank" href="https://github.com/Azure/mmlspark">https://github.com/Azure/mmlspark</a> )Regarding mmlspark, please refer to the following paper: <a target="_blank" href="https://arxiv.org/pdf/1810.08744.pdf">https://arxiv.org/pdf/1810.08744.pdf</a>`,
}
}

export default en;

+ 12
- 0
web_src/vuepages/langs/config/zh-CN.js View File

@@ -40,6 +40,7 @@ const zh = {
inferenceTask: "推理任务",
benchmarkTask: "评测任务",
onlineinfer: "在线推理",
superComputeTask: "超算任务",
createPublicProject: "创建公开项目",
dailyPutforwardTasks: "每日提出任务",
dailyPR: "每日提出PR",
@@ -545,8 +546,13 @@ const zh = {
taskPrepareTips: '任务正在准备中,喝杯水回来再看看~',
waitCountStart: '您当前排队位置是第',
waitCountEnd: '位',
task: '任务',
taskList: '任务列表',
taskName: '任务名称',
appName: '应用名称',
appList: '应用列表',
taskNameTips: '只能以小写字母或数字开头且只包含小写字母、数字、_和-,不能以_结尾,最长36个字符。',
taskNameTips1: '只能以小写字母开头,包含数字、小写字母和短横线(-),长度为5~26个字符。',
taskDescr: '任务描述',
taskDescrPlaceholder: '描述字数不超过255个字符',
codeBranch: '代码分支',
@@ -584,6 +590,7 @@ const zh = {
stop: '停止',
modify: '修改',
delete: '删除',
startUse: '开始使用',
more: '更多',
commitImage: '提交镜像',
downloadModel: '模型下载',
@@ -617,6 +624,7 @@ const zh = {
debugTaskEmptyTip3: '使用说明:可以参考启智AI协作平台 <a href="{url}" target="_blank">帮助中心</a>。',
onlineInferTaskEmptyTitle: '未创建过在线推理任务',
onlineInferEmptyTip2: '数据集:云脑1提供 CPU / GPU 资源,云脑2提供 Ascend NPU 资源,在线推理使用的数据集也需要上传到对应的环境;',
superTaskEmptyTitle: '未创建过超算任务',
deleteConfirmTips: '您确认删除该任务么?此任务一旦删除不可恢复。',
deletingTips: '任务删除中,请稍后',
tabTitDebug: '调试任务',
@@ -661,6 +669,10 @@ const zh = {


},
superComputeObj: {
mmlSparkDescr: `MMLSpark全称为Microsoft Machine Learning for Apache Spark,支持用户运行自制容器镜像,且赋予了用户容器内root权限。用户可直接使用平台提供的微软的MMLSpark。\n注:MMLSpark是微软提供针对机器学习环境的Spark版本(<a target="_blank" href="https://github.com/Azure/mmlspark">https://github.com/Azure/mmlspark</a>),关于mmlspark可参考论文:<a target="_blank" href="https://arxiv.org/pdf/1810.08744.pdf">https://arxiv.org/pdf/1810.08744.pdf</a>`,
}

}

export default zh;

+ 7
- 7
web_src/vuepages/pages/resources/components/SpecSelect.vue View File

@@ -27,14 +27,14 @@
<div class="row-r" style="flex:1">{{ $t('resourcesManagement.resQueue') }}</div>
</div>
<div class="table-content">
<div class="row" v-for="item in tableData1">
<div class="row" v-for="(item, index) in tableData1" :key="index">
<div class="row-l" style="width:600px;">{{ item.SpecStr }}</div>
<div class="row-r" style="flex:1">
<div class="btn-c">
<button @click="selectAll(item.queues)">{{ $t('selectAll') }}</button>
<button @click="clearSelectAll(item.queues)">{{ $t('selectNone') }}</button>
</div>
<div class="" v-for="_item in item.queues">
<div class="" v-for="_item in item.queues" :key="_item.ID">
<el-checkbox :value="_item.checked" @change="selectChange(_item.ID)">
<span v-html="_item.QueueStr + _item.PriceStr + _item.StatusStr"></span>
</el-checkbox>
@@ -50,14 +50,14 @@
<div class="row-r" style="flex:1">{{ $t('resourcesManagement.resourceSpecification') }}</div>
</div>
<div class="table-content">
<div class="row" v-for="item in tableData2">
<div class="row" v-for="(item, index) in tableData2" :key="index">
<div class="row-l" style="width:400px;">{{ item.QueueStr }}</div>
<div class="row-r" style="flex:1">
<div class="btn-c">
<button @click="selectAll(item.specs)">{{ $t('selectAll') }}</button>
<button @click="clearSelectAll(item.specs)">{{ $t('selectNone') }}</button>
</div>
<div class="" v-for="_item in item.specs">
<div class="" v-for="_item in item.specs" :key="_item.ID">
<el-checkbox :value="_item.checked" @change="selectChange(_item.ID)">
<span v-html="_item.SpecStr + _item.PriceStr + _item.StatusStr"></span>
</el-checkbox>
@@ -83,10 +83,10 @@
<div class="row-r" style="flex:1">{{ $t('resourcesManagement.resQueue') }}</div>
</div>
<div class="table-content">
<div class="row" v-for="item in tableDataShow">
<div class="row" v-for="(item, index) in tableDataShow" :key="index">
<div class="row-l" style="width:400px;">{{ item.SpecStr }}</div>
<div class="row-r" style="flex:1">
<div class="" v-for="_item in item.queues">
<div class="" v-for="(_item, _index) in item.queues" :key="_index">
<span v-html="_item.QueueStr + _item.PriceStr + _item.StatusStr"></span>
</div>
</div>
@@ -397,7 +397,7 @@ export default {
}

.dlg-content {
margin: -30px 0 0 0;
margin: 0px 0 0 0;
display: flex;
font-size: 12px;



+ 186
- 0
web_src/vuepages/pages/supercompute/apps/index.vue View File

@@ -0,0 +1,186 @@
<template>
<div>
<div class="ui container">
<div class="header">
<div class="tab-c">
<a class="tab-item" :href="`/${repoOwnerName}/${repoName}/${item.url}`" :key="item.key"
:class="item.type == curTab ? 'focus' : ''" v-for="item in tabs">
<span>{{ item.label }}</span>
</a>
</div>
<div class="right-c"></div>
</div>
<div class="list">
<div class="item-c" v-for="(item, index) in apps" :key="index">
<el-tooltip class="item-tool-tips" effect="light" placement="bottom">
<a class="item" :href="`/${repoOwnerName}/${repoName}/supercompute/job/create?type=${item.type}`">
<div class="logo">
<img :src="item.logo" alt="" />
</div>
<div class="name"> {{ item.name }}</div>
</a>
<div slot="content" class="item-tool-tip-content" v-html="item.descr"></div>
</el-tooltip>
</div>
</div>
</div>
<LoadingMask :loading="maskLoading" :content="maskLoadingContent"></LoadingMask>
</div>
</template>

<script>
import LoadingMask from '~/components/cloudbrain/LoadingMask.vue';
import { TABS } from '../configs';

export default {
data() {
return {
curTab: 'app',
tabs: [...TABS],
repoOwnerName: location.pathname.split('/')[1],
repoName: location.pathname.split('/')[2],
apps: [{
type: 'MMLSpark',
name: 'MMLSpark',
logo: '/img/supercompute/mmlspark.jpg',
descr: this.$t('superComputeObj.mmlSparkDescr'),
}],
maskLoading: false,
maskLoadingContent: '',
};
},
components: {
LoadingMask
},
methods: {},
beforeMount() { },
mounted() { },
beforeDestroy() { },
};
</script>

<style scoped lang="less">
@import '~/components/cloudbrain/cloudbrain.less';

.header {
margin-bottom: 26px;
display: flex;
align-items: center;
justify-content: space-between;

.tab-c {
display: flex;
align-items: center;

.tab-item {
display: flex;
align-items: center;
justify-content: center;
font-size: 13px;
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;

&.focus {
color: #0087f5;
border-color: #0087f5;
border-left: 1px solid #0087f5;
}

&:first-child {
border-radius: 0.28571429rem 0 0 0.28571429rem;
border-left: 1px solid rgba(34, 36, 38, .15);

&.focus {
border-color: #0087f5;
}
}

&:last-child {
border-radius: 0 0.28571429rem 0.28571429rem 0;
}

&:hover:not(.focus) {
background: rgba(0, 0, 0, .03);
}
}
}

.right-c {
display: flex;
align-items: center;
}
}

.list {
display: flex;
flex-wrap: wrap;

.item-c {
width: 288px;
height: 221px;
display: flex;

.item {
flex: 1;
margin: 10px;
border-radius: 4px;
cursor: pointer;
box-shadow: 0px 4px 4px 0px rgba(232, 232, 232, 0.6);
border: 1px solid #e8e8e8 !important;
padding: 16px;

.logo {
height: 140px;
box-shadow: 0px 1px 1px 0px rgba(232, 232, 232, 0.6);

img {
height: 100%;
width: 100%;
object-fit: cover;
}
}

.name {
text-align: center;
font-size: 16px;
font-weight: bold;
margin-top: 12px;
color: #0366D6;
}
}
}
}

.item-tool-tips {
.el-tooltip__popper .popper__arrow {
/* 上方箭头 */
border-top-color: #fff !important;
/* 下方箭头 */
border-bottom-color: #fff !important;
}

.el-tooltip__popper .popper__arrow:after {
border-top-color: #fff !important;
border-bottom-color: #fff !important;
}

/* tooltip主体部分 */
.el-tooltip__popper {
padding: 0 !important;
border-radius: 4px !important;
border-color: #e6e6e6 !important;
box-shadow: 0px 0px 7px 0px rgba(42, 42, 42, 0.2) !important;
}
}


.item-tool-tip-content {
width: 402px;
word-wrap: break-word;
white-space: pre-wrap;
}
</style>

+ 17
- 0
web_src/vuepages/pages/supercompute/apps/vp-cloudbrain-super-apps.js View File

@@ -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');

+ 94
- 0
web_src/vuepages/pages/supercompute/configs.js View File

@@ -0,0 +1,94 @@
import { i18n } from '~/langs';

export const TABS = [{
type: 'app',
url: 'supercompute',
label: i18n.t('cloudbrainObj.appList'),
}, {
type: 'task',
url: 'supercompute/job',
label: i18n.t('cloudbrainObj.taskList'),
}];

export const ListPageConfigs = {
page: {
clusterType: 'C2Net',
computerResouce: 'CPU',
appName: 'MMLSpark',
jobType: 'SUPERCOMPUTE',
jobTypeName: i18n.t('superComputeTask'),
columns: ['taskName', 'status', 'appName', 'createTime', 'runDuration', 'clusterAndComputeResource', 'creator'],
operations: ['start', 'stop', 'delete'],
emptyTitle: i18n.t('cloudbrainObj.superTaskEmptyTitle'),
emptyTip0: true,
emptyTip1: '',
emptyTip2: '',
emptyTip3: i18n.t('cloudbrainObj.debugTaskEmptyTip3', { url: 'https://openi.pcl.ac.cn/docs/index.html#/supercompute/mmlspark' }),
}
};

export const CreatePageConfigs = {
'MMLSpark': {
appListUrl: 'supercompute',
taskListUrl: 'supercompute/job',
taskType: 'SUPERCOMPUTE',
taskTypeName: i18n.t('superComputeTask'),
clusterType: 'C2Net',
computerResouce: 'CPU',
appName: 'MMLSpark',
hideCluster: true,
hideComputerResource: true,
tips2: i18n.t('cloudbrainObj.pathTips3', {
code: '/code',
dataset: '/dataset',
model: '/pretrainmodel',
}),
form: {
taskName: { required: true, },
taskDescr: { required: false, },
branchName: {},
model: { required: false, multiple: true },
imagev2: { required: true },
dataset: { required: false },
spec: { required: true },
},
}
};

export const DetailPageConfigs = {
'MMLSpark': {
listUrl: 'supercompute/job',
summary: [],
operations: [],
tabs: [{
name: 'configInfo',
fields: [
'taskName', 'appName',
'status', 'imagev2',
'creator', 'spec',
'branch', 'aiCenter',
'computerRes', 'modelName',
'createTime', 'modelVersion',
'startTime', 'modelFiles',
'endTime', '',
'duration', '',
'descr', '',
'failedReason',
'dataset',
'modelList',
]
}],
}
};

export const getAiJobLink = (taskInfo) => {
return `supercompute/job/${taskInfo.id}`;
};

export const getCreatePageConfigs = (appName) => {
return CreatePageConfigs[appName] || CreatePageConfigs['MMLSpark'];
};

export const getDetailPageConfigs = (appName) => {
return DetailPageConfigs[appName];
};

+ 406
- 0
web_src/vuepages/pages/supercompute/create/index.vue View File

@@ -0,0 +1,406 @@
<template>
<div>
<div class="ui container" v-if="errorMsgBoxShow">
<div class="err-msg-box">
<p>{{ errorMsg }}</p>
</div>
</div>
<div class="ui container">
<div class="head-path">
<a class="section" :href="`/${repoOwnerName}/${repoName}/supercompute`">{{ $t('cloudbrainObj.appList') }}</a>
<span class="divider">/</span>
<span class="section active">{{ $t('cloudbrainObj.create') }}{{ $t('superComputeTask') }}</span>
</div>
<div class="form-container">
<div class="form-head">
<h4>{{ $t('cloudbrainObj.create') }}{{ pageCfg.appName }}{{ $t('cloudbrainObj.task') }}</h4>
</div>
<div class="ui container" v-if="alreadyMsgBoxShow">
<div class="err-msg-box-already">
<div class="msg-content">
<i class="ri-information-line"></i>
<div class="msg-content-tip">
<div class="line-1" v-html="$t('cloudbrainObj.sameTaskTips1')"></div>
<div class="line-2" v-html="$t('cloudbrainObj.sameTaskTips2')"></div>
</div>
</div>
</div>
</div>
<div class="form-body">
<div class="form-body-content">
<div class="main-title">{{ $t('cloudbrainObj.basicInfo') }}:</div>
<FormTop ref="formTopRef" :repoOwnerName="repoOwnerName" :repoName="repoName" :configs="pageCfg"
:queueNum="queueNum"></FormTop>
<TaskName ref="taskNameRef" v-if="formCfg.taskName" v-model="state.taskName" autofocus type="supercompute"
:required="formCfg.taskName.required" :userName="repoOwnerName">
</TaskName>
<TaskDescr ref="taskDescrRef" v-if="formCfg.taskDescr" v-model="state.taskDescr"
:required="formCfg.taskDescr.required"></TaskDescr>
</div>
<div class="line"></div>
<div class="form-body-content">
<div class="main-title params-setting">{{ $t('cloudbrainObj.paramsSetting') }}:</div>
<BranchName ref="branchNameRef" v-if="formCfg.branchName" v-model="state.branchName"
:required="formCfg.branchName.required" :branches="branchList">
</BranchName>
<ModelSelect ref="modelRef" v-if="formCfg.model" v-model="state.model" :required="formCfg.model.required"
:multiple="formCfg.model.multiple" :repoOwnerName="repoOwnerName" :repoName="repoName"></ModelSelect>
<ImageSelectV2 ref="imagev2Ref" v-if="formCfg.imagev2" v-model="state.image" :images="imageList"
:required="formCfg.imagev2.required">
</ImageSelectV2>
<DatasetSelect ref="datasetRef" v-if="formCfg.dataset" v-model="state.dataset"
:required="formCfg.dataset.required" :type="formCfg.dataset.type != undefined ? formCfg.dataset.type : -1"
:repoOwnerName="repoOwnerName" :repoName="repoName" :exceedSize="datasetSize"></DatasetSelect>
<SpecSelect ref="specRef" v-if="formCfg.spec" v-model="state.spec" :required="formCfg.spec.required"
:configs="specConfigs" :workServerNum="state.workServerNum"></SpecSelect>
<div class="form-row">
<div class="title"></div>
<div class="content">
<el-button type="primary" :disabled="maskLoading || alreadyMsgBoxShow || noSpecFlag" size="default"
class="submit-btn" @click="submit">{{ $t('cloudbrainObj.createTask') }}</el-button>
<el-button class="cancel-btn" size="default" @click="cancel">{{ $t('cancel') }}</el-button>
</div>
</div>
</div>
</div>
</div>
</div>
<LoadingMask :loading="maskLoading" :content="maskLoadingContent"></LoadingMask>
</div>
</template>

<script>
import FormTop from '~/components/cloudbrain/FormTop.vue';
import TaskName from '~/components/cloudbrain/TaskName.vue';
import TaskDescr from '~/components/cloudbrain/TaskDescr.vue';
import BranchName from '~/components/cloudbrain/BranchName.vue';
import ModelSelect from '~/components/cloudbrain/ModelSelect.vue';
import ImageSelectV2 from '~/components/cloudbrain/ImageSelectV2.vue';
import DatasetSelect from '~/components/cloudbrain/DatasetSelect.vue';
import SpecSelect from '~/components/cloudbrain/SpecSelect.vue';
import LoadingMask from '~/components/cloudbrain/LoadingMask.vue';
import { getCreatePageConfigs } from '../configs';
import { getUrlSearchParams } from '~/utils';
import { getAiTaskPrepareInfo, createAiTask } from '~/apis/modules/cloudbrain';

export default {
data() {
return {
pageCfg: {},
formCfg: {},
cancelUrl: '',
successUrl: '',
repoOwnerName: location.pathname.split('/')[1],
repoName: location.pathname.split('/')[2],
state: {
taskName: '',
taskDescr: '',
branchName: '',
model: [],
image_url: '',
image: {},
dataset: [],
spec: '',
},
branchList: [],
imageList: [],
specConfigs: {
specs: [],
blance: 0,
showPoint: false,
},
queueNum: 1,

errorMsgBoxShow: false,
errorMsg: '',
alreadyMsgBoxShow: false,
maskLoading: false,
maskLoadingContent: '',
datasetSize: 0,
noSpecFlag: false,
};
},
components: {
FormTop, TaskName, TaskDescr, BranchName, ImageSelectV2, ModelSelect, DatasetSelect, SpecSelect,
LoadingMask
},
methods: {
submit() {
if (this.maskLoading) return;
let canSubmit = true;
for (let key in this.formCfg) {
if (this.$refs[key + 'Ref']) {
if (!this.$refs[key + 'Ref'].check()) {
canSubmit = false;
}
}
}
if (!canSubmit) return;
const subObj = {
repoOwnerName: this.repoOwnerName,
repoName: this.repoName,
job_type: this.pageCfg.taskType,
cluster: this.pageCfg.clusterType,
compute_source: this.pageCfg.computerResouce,
app_name: this.pageCfg.appName,
};
for (let key in this.formCfg) {
switch (key) {
case 'taskName':
subObj['display_job_name'] = this.state.taskName;
break;
case 'taskDescr':
subObj['description'] = this.state.taskDescr;
break;
case 'branchName':
subObj['branch_name'] = this.state.branchName;
break;
case 'model':
const modelInfo = this.state.model[0] || {};
const pretrain_model_ckpt_name = this.state.model.map(item => item.FileName).join(';');
subObj['pretrain_model_id'] = modelInfo._modelID || '';
subObj['pretrain_model_name'] = modelInfo._modelName || '';
subObj['pretrain_model_version'] = modelInfo._modelVersion || '';
subObj['pretrain_model_ckpt_name'] = pretrain_model_ckpt_name || '';
subObj['pretrain_model_url'] = modelInfo._preTrainModelUrl || '';
break;
case 'imagev2':
subObj['image_id'] = this.state.image.image_id;
subObj['image_name'] = this.state.image.image_name;
break;
case 'dataset':
subObj['dataset_uuid_str'] = this.state.dataset.map(item => item.id).join(';');
break;
case 'spec':
subObj['spec_id'] = Number(this.state.spec);
break;
default:
break;
}
}
// console.log('subObj', subObj);
// return;
this.maskLoadingContent = this.$t('cloudbrainObj.taskPrepareTips');
this.maskLoading = true;
this.errorMsg = '';
this.errorMsgBoxShow = false;
createAiTask(subObj).then(res => {
const data = res.data;
if (data.code == 0) {
this.goTaskList();
} else {
this.maskLoading = false;
this.errorMsg = data.msg;
this.errorMsgBoxShow = true;
}
}).catch(err => {
this.maskLoading = false;
console.log(err);
});
},
cancel() {
if (this.cancelUrl) {
window.location.href = this.cancelUrl;
} else {
window.history.back();
}
},
goTaskList() {
window.location.href = this.successUrl;
}
},
beforeMount() {
const urlParams = getUrlSearchParams();
const appName = urlParams.type;
const configs = getCreatePageConfigs(appName);
this.pageCfg = configs;
this.formCfg = configs.form;
this.cancelUrl = `/${this.repoOwnerName}/${this.repoName}/${configs.appListUrl}`;
this.successUrl = `/${this.repoOwnerName}/${this.repoName}/${configs.taskListUrl}`;
if (urlParams.backurl) {
this.cancelUrl = urlParams.backurl;
}
if (!configs.taskType || !configs.clusterType || !configs.computerResouce) {
console.log(`page configs error.`);
this.cancel();
return;
}
getAiTaskPrepareInfo({
repoOwnerName: this.repoOwnerName,
repoName: this.repoName,
jobType: configs.taskType,
clusterType: configs.clusterType,
computeSource: configs.computerResouce,
appName: configs.appName,
}).then(res => {
res = res.data;
if (res.code == 0) {
const data = res.data;
this.branchList = data.branches || [];
this.imageList = data.images || [];
this.alreadyMsgBoxShow = data.not_stop_task_count > 0;
this.specConfigs.showPoint = data.pay_switch;
this.specConfigs.blance = data.point_account ? data.point_account.balance : 0;
this.specConfigs.specs = data.specs || [];
if (!this.specConfigs.specs.length) {
this.noSpecFlag = true
}
this.queueNum = data.wait_count || 1;
this.state.branchName = data.default_branch;
this.state.taskName = data.display_job_name;
this.state.spec = this.specConfigs.specs.length ? this.specConfigs.specs[0].id.toString() : '';
this.state.image = this.imageList.length ? {
image_id: this.imageList[0].image_id,
image_name: this.imageList[0].image_name,
} : {};
if (data.config && data.config.dataset_max_size) {
this.datasetSize = data.config.dataset_max_size;
}
} else {

}
}).catch(err => {
console.log(err);
});
},
mounted() { },
beforeDestroy() { },
};
</script>

<style scoped lang="less">
@import '~/components/cloudbrain/cloudbrain.less';

.err-msg-box {
display: flex;
align-items: center;
justify-content: center;
background-color: #fff6f6;
color: #9f3a38;
box-shadow: 0 0 0 1px #e0b4b4 inset, 0 0 0 0 transparent;
margin: 1em 0;
padding: 1em 1.5em;
border-radius: 0.28571429rem;
transition: opacity .1s ease, color .1s ease, background .1s ease, box-shadow .1s ease, -webkit-box-shadow .1s ease;

>p {
opacity: .85;
}
}

.err-msg-box-already {
margin: 1em 0;
padding: 1em 1.5em;
background-color: rgba(242, 113, 28, 0.05);
border: 1px solid rgba(242, 113, 28, 1);
border-radius: 5px;

.msg-content {
display: flex;
align-items: center;

i {
font-size: 35px;
color: rgba(242, 113, 28, 1);
}

.msg-content-tip {
text-align: left;
margin-left: 1rem;

.line-1 {
font-weight: 600;
line-height: 2;

span {
color: rgba(242, 113, 28, 1);
}
}

.line-2 {
color: #939393
}
}
}
}

.head-path {
margin-top: -0.14285714em;
margin-bottom: 1rem;

.section {
display: inline-block;
margin: 0;
padding: 0;
color: #4183c4;
line-height: 1.4285em;
font-size: 1rem;
font-weight: 700;
cursor: pointer;

&.active {
color: rgba(0, 0, 0, .87);
cursor: default;
}

&:hover {
&:not(.active) {
color: #1e70bf;
}
}
}

.divider {
display: inline-block;
opacity: .7;
margin: 0 0.21428571rem 0;
font-size: .92857143em;
color: rgba(0, 0, 0, .4);
vertical-align: baseline;
}
}

.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;

.main-title {
color: #101010;
font-size: 16px;
padding-left: 5rem;
font-weight: 700;
line-height: 1.28571429em;
margin: 16px 0;
}
}

.line {
border-top: 1px solid rgba(34, 36, 38, .15);
border-bottom: 1px solid rgba(255, 255, 255, .1);
margin: 1rem 0 2rem;
}
}
}

/deep/ .form-row .content {
width: 65%;
}
</style>

+ 17
- 0
web_src/vuepages/pages/supercompute/create/vp-cloudbrain-super-create.js View File

@@ -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');

+ 332
- 0
web_src/vuepages/pages/supercompute/detail/index.vue View File

@@ -0,0 +1,332 @@
<template>
<div style="min-height:400px;">
<div v-if="notFound">
<NotFound></NotFound>
</div>
<div v-else>
<div v-if="!loading" class="ui container">
<div class="head-path">
<a class="section" :href="`/${repoOwnerName}/${repoName}/${pageCfg.listUrl}`">{{ $t('cloudbrainObj.taskList')
}}</a>
<span class="divider">/</span>
<span class="section active">{{ mainData[0] ? mainData[0].task.display_job_name : '' }}</span>
</div>
<div class="body-content">
<el-collapse class="collapse" accordion v-model="collapseValue" @change="taskChange">
<el-collapse-item class="collapse-item" v-for="(item, index) in mainData" :key="index"
:name="index.toString()">
<template slot="title">
<div class="title" @click.stop.prevent="">
<div class="title-l">
<span class="task-create-time">{{ item.task.createTimeStr }}</span>
<span class="task-status">
<span>{{ $t('status') }}:</span><i :class="item.task.status"></i><span>{{ item.task.status }}</span>
</span>
<span class="task-duration">
<span>{{ $t('cloudbrainObj.runDuration') }}:</span><span>{{ item.task.formatted_duration }}</span>
</span>
<span class="task-refresh">
<el-tooltip placement="top" :content="$t('cloudbrainObj.refresh')">
<i class="el-icon-refresh-right" @click.stop.prevent="refresh(item)"></i>
</el-tooltip>
</span>
</div>
<div class="title-r"></div>
</div>
</template>
<div class="content">
<el-tabs v-model="item.activeName" @tab-click="tabChange(item)">
<el-tab-pane v-if="tabNameList.indexOf('configInfo') >= 0"
:label="$t('cloudbrainObj.configurationInfo')" :name="`configInfo-` + item.task.id">
<ConfigInfo :ref="`configInfo-` + item.task.id + '-Ref'" :data="item"
:configs="tabConfigs['configInfo']">
</ConfigInfo>
</el-tab-pane>
</el-tabs>
</div>
</el-collapse-item>
</el-collapse>
</div>
</div>
</div>
<LoadingMask :loading="maskLoading" :content="maskLoadingContent"></LoadingMask>
</div>
</template>

<script>
import NotFound from '~/components/NotFound.vue';
import LoadingMask from '~/components/cloudbrain/LoadingMask.vue';
import ConfigInfo from '~/components/cloudbrain/details/ConfigInfo.vue';
import { CloudBrainTools } from '~/pages/cloudbrain/tools';
import { CLUSTERS } from '~/const';
import { timeSinceUnix, getListValueWithKey } from '~/utils';
import { getDetailPageConfigs, getAiJobLink } from '../configs';
import { getAiTask } from '~/apis/modules/cloudbrain';
import { formatDate } from 'element-ui/lib/utils/date-util';

const cloudBrainTools = new CloudBrainTools();

export default {
data() {
return {
notFound: false,
pageCfg: {},
tabNameList: [],
tabConfigs: {},
operationList: [],
repoOwnerName: location.pathname.split('/')[1],
repoName: location.pathname.split('/')[2],
state: {},
collapseValue: '0',
mainData: [],
loading: false,
errorMsgBoxShow: false,
errorMsg: '',
maskLoading: false,
maskLoadingContent: '',
};
},
components: { NotFound, LoadingMask, ConfigInfo },
methods: {
taskChange(taskIndex) {
const item = this.mainData[Number(taskIndex)];
item.activeName = 'configInfo-' + item.task.id;
},
tabChange(item) {
this.$nextTick(() => {
this.refresh(item);
});
},
refresh(item) {
const activeTab = item.activeName;
const tabContent = this.$refs[activeTab + '-Ref'];
if (activeTab.indexOf('configInfo-') > -1) {
const task = item.task;
const taskId = task.id;
getAiTask({
repoOwnerName: task.repoOwnerName,
repoName: task.repoName,
id: taskId,
}).then(res => {
res = res.data;
if (res.code == 0) {
Object.assign(task, res.data.task);
delete res.data.task;
delete res.data.early_version_list;
Object.assign(item, res.data);
Object.assign(task, res.data);
task.createdFromNow = timeSinceUnix(task.created_unix, Date.now() / 1000);
task.createTimeStr = formatDate(new Date(task.created_unix * 1000), 'yyyy-MM-dd HH:mm:ss');
cloudBrainTools.checkOperation(task);
}
}).catch(err => {
console.log(err);
});
} else {
tabContent && tabContent[0] && tabContent[0].refresh && tabContent[0].refresh();
}
}
},
beforeMount() {
const taskId = window.location.pathname.split('/').pop();
this.loading = true;
getAiTask({
repoOwnerName: this.repoOwnerName,
repoName: this.repoName,
id: taskId,
}).then(res => {
this.loading = false;
res = res.data;
if (res.code == 0 && res.data) {
const earlyVersionList = (res.data.early_version_list || []).map(item => {
return Object.assign({}, res.data, { task: item });
});
const data = [res.data, ...earlyVersionList];
let appName = '';
data.forEach(item => {
const task = item.task;
appName = task.app_name;
task.computeSourceShow = task.compute_source == 'GPU' ? 'CPU/GPU' : task.compute_source;
item.activeName = 'configInfo-' + task.id;
task.clusterName = getListValueWithKey(CLUSTERS, task.cluster);
task.repoOwnerName = this.repoOwnerName;
task.repoName = this.repoName;
task.jobLink = `/${this.repoOwnerName}/${this.repoName}/${getAiJobLink(task)}`;
task.createdFromNow = timeSinceUnix(task.created_unix, Date.now() / 1000);
task.createTimeStr = formatDate(new Date(task.created_unix * 1000), 'yyyy-MM-dd HH:mm:ss');
cloudBrainTools.checkOperation(task);
});
const configs = getDetailPageConfigs(appName) || {};
this.pageCfg = configs;
const tabs = this.pageCfg.tabs || [];
const tabsName = tabs.map(item => item.name);
const tabConfigs = {};
tabs.forEach(item => {
tabConfigs[item.name] = item;
});
this.tabNameList = tabsName;
this.tabConfigs = tabConfigs;
this.operationList = this.pageCfg.operations || [];
this.mainData = data;
cloudBrainTools.initRefreshData(this.mainData);
} else {
this.notFound = true;
}
}).catch(err => {
this.loading = false;
this.notFound = true;
console.log(err);
});
},
mounted() { },
};
</script>

<style scoped lang="less">
.head-path {
margin-top: -0.14285714em;
margin-bottom: 1rem;

.section {
display: inline-block;
margin: 0;
padding: 0;
color: #4183c4;
line-height: 1.4285em;
font-size: 1rem;
font-weight: 700;
cursor: pointer;

&.active {
color: rgba(0, 0, 0, .87);
cursor: default;
}

&:hover {
&:not(.active) {
color: #1e70bf;
}
}
}

.divider {
display: inline-block;
opacity: .7;
margin: 0 0.21428571rem 0;
font-size: .92857143em;
color: rgba(0, 0, 0, .4);
vertical-align: baseline;
}
}

.body-content {
.collapse-item {
border: 1px solid #dfe1e6;
margin-top: -1px;

/deep/ div[role="tab"] {
div[role="button"] {
height: 40px;
box-sizing: border-box;
padding: 8px 16px;
color: #252b3a;
background-color: #f2f5fc;
line-height: 1.5;
cursor: default;
position: relative;

.title {
height: 100%;
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;

.title-l {
display: flex;
align-items: center;
cursor: default;
font-size: 12px;
padding-left: 18px;

.task-create-time {
margin-right: 12px;
}

.task-status {
display: flex;
align-items: center;
margin-right: 12px;

i {
margin-right: 4px;
}
}

.task-duration {
display: flex;
align-items: center;
margin-right: 6px;
}

.task-refresh {
display: flex;
align-items: center;

i {
font-size: 14px;
font-weight: 600;
color: #3291F8;
cursor: pointer;
}
}
}

.title-r {
display: flex;
align-items: center;

.ops-btn {
margin-right: 10px;
padding-right: 11px;
font-size: 13px;
border-right: 1px solid #dfe1e6;
line-height: 14px;

&:last-child {
border-right: none;
padding-right: 0;
margin-right: 0;
}

&.btn-disabled {
cursor: not-allowed;
opacity: 0.45 !important;
}
}
}
}
}

.el-icon-arrow-right {
position: absolute;
margin-top: -2px;
font-size: 13px;

&::before {
content: "\e791";
cursor: pointer;
}
}
}

/deep/ div.el-collapse-item__wrap[role="tabpanel"] {
padding: 15px 35px 5px;

.el-collapse-item__content {
padding-bottom: 0;
}
}
}
}
</style>

+ 17
- 0
web_src/vuepages/pages/supercompute/detail/vp-cloudbrain-super-detail.js View File

@@ -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');

+ 559
- 0
web_src/vuepages/pages/supercompute/list/index.vue View File

@@ -0,0 +1,559 @@
<template>
<div>
<div class="ui container">
<div class="header">
<div class="tab-c">
<a class="tab-item" :href="`/${repoOwnerName}/${repoName}/${item.url}`" :key="item.key"
:class="item.type == curTab ? 'focus' : ''" v-for="item in tabs">
<span>{{ item.label }}</span>
</a>
</div>
<div class="right-c"></div>
</div>
<div v-if="tableData.length > 0">
<div class="list-body table-container">
<el-table :data="tableData" style="min-width:100%" v-loading="loading" stripe>
<el-table-column v-if="pageCfg.page.columns.indexOf('taskName') >= 0" :label="$t('cloudbrainObj.taskName')"
align="left" header-align="left" min-width="250">
<template slot-scope="scope">
<a class="dispaly-job-name" :href="scope.row.task.jobLink">
{{ scope.row.task.display_job_name }}
</a>
</template>
</el-table-column>
<el-table-column v-if="pageCfg.page.columns.indexOf('status') >= 0" prop="Status" :label="$t('status')"
align="left" header-align="left" min-width="120">
<template slot-scope="scope">
<div class="status-wrap">
<i :class="scope.row.task.status"></i>
<span>{{ scope.row.task.status }}</span>
</div>
</template>
</el-table-column>
<el-table-column v-if="pageCfg.page.columns.indexOf('appName') >= 0" prop="job_type"
:label="$t('cloudbrainObj.appName')" align="center" header-align="center" min-width="120">
<template slot-scope="scope">
<span>{{ scope.row.task.app_name }}</span>
</template>
</el-table-column>
<el-table-column v-if="pageCfg.page.columns.indexOf('createTime') >= 0" prop="created_unix"
:label="$t('cloudbrainObj.createTime')" align="center" header-align="center" min-width="120">
<template slot-scope="scope">
<el-tooltip effect="dark" :content="dateFormat(scope.row.task.created_unix)" placement="top-start">
<span>{{ scope.row.task.createdFromNow }}</span>
</el-tooltip>
</template>
</el-table-column>
<el-table-column v-if="pageCfg.page.columns.indexOf('runDuration') >= 0" prop="formatted_duration"
:label="$t('cloudbrainObj.runDuration')" align="center" header-align="center" min-width="120">
<template slot-scope="scope">
<span>{{ scope.row.task.formatted_duration }}</span>
</template>
</el-table-column>
<el-table-column v-if="pageCfg.page.columns.indexOf('clusterAndComputeResource') >= 0"
:label="$t('cloudbrainObj.clusterAndComputeResource')" align="center" header-align="center" min-width="150">
<template slot-scope="scope">
<span>{{ scope.row.task.clusterName }}&nbsp;{{ scope.row.task.computeSourceShow }}</span>
</template>
</el-table-column>
<el-table-column v-if="pageCfg.page.columns.indexOf('creator') >= 0" prop="remark"
:label="$t('modelManage.creator')" align="left" min-width="80" header-align="center">
<template slot-scope="scope">
<div class="creator-wrap">
<a :href="'/' + scope.row.creator.name" :title="scope.row.creator.full_name">
<img :src="scope.row.creator.rel_avatar_link">
</a>
</div>
</template>
</el-table-column>
<el-table-column prop="remark" :label="$t('operation')" align="left" min-width="300" header-align="center">
<template slot-scope="scope">
<div class="op-wrap">
<a href="javascript:;"
v-if="pageCfg.page.operations.indexOf('start') >= 0 && scope.row.can_modify && scope.row.task.canDebug"
@click="opDebug(scope.row)"
:class="scope.row.can_modify && scope.row.task.canDebug ? '' : 'disabled'">{{
$t('cloudbrainObj.startUse')
}}</a>
<a href="javascript:;" v-if="pageCfg.page.operations.indexOf('stop') >= 0" @click="opStop(scope.row)"
:class="scope.row.can_delete && scope.row.task.canStop ? '' : 'disabled'">{{ $t('cloudbrainObj.stop')
}}</a>
<a href="javascript:;" v-if="pageCfg.page.operations.indexOf('delete') >= 0"
@click="opDelete(scope.row)"
:class="scope.row.can_delete && scope.row.task.canDelete ? '' : 'disabled'">{{
$t('cloudbrainObj.delete') }}</a>
</div>
</template>
</el-table-column>
</el-table>
</div>
<div class="list-foot">
<el-pagination ref="paginationRef" background @current-change="currentChange" @size-change="sizeChange"
:current-page.sync="page" :page-sizes="pageSizes" :page-size.sync="pageSize"
layout="total, sizes, prev, pager, next, jumper" :total="total">
</el-pagination>
</div>
<div v-if="false" class="foot-tips" v-html="$t('cloudbrainObj.maxTaskTips')"></div>
</div>
<div class="empty-page" v-if="!loading && tableData.length == 0">
<div class="empty-icon"></div>
<div class="empty-title">{{ pageCfg.page.emptyTitle }}</div>
<div class="empty-content">
<div v-if="pageCfg.page.emptyTip0 && isRepoEmpty"
v-html="$t('cloudbrainObj.debugTaskEmptyTip0', { url: `/${repoOwnerName}/${repoName}` })"></div>
<div v-if="pageCfg.page.emptyTip1" v-html="pageCfg.page.emptyTip1"></div>
<div v-if="pageCfg.page.emptyTip2" v-html="pageCfg.page.emptyTip2"></div>
<div v-if="pageCfg.page.emptyTip3" v-html="pageCfg.page.emptyTip3"></div>
</div>
</div>
</div>
<LoadingMask :loading="maskLoading" :content="maskLoadingContent"></LoadingMask>
<el-dialog class="task-already-dlg" :visible.sync="taskAlreadyDialogShow" :lock-scroll="false" :show-close="false">
<div class="err-msg-box-already">
<div class="msg-content">
<i class="ri-information-line"></i>
<div class="msg-content-tip">
<div class="line-1" v-html="$t('cloudbrainObj.sameTaskTips1')"></div>
<div class="line-2" v-html="$t('cloudbrainObj.sameTaskTips2')"></div>
</div>
</div>
</div>
</el-dialog>
</div>
</template>

<script>
import LoadingMask from '~/components/cloudbrain/LoadingMask.vue';
import { ListPageConfigs, getAiJobLink } from '../configs';
import { TABS } from '../configs';
import { CloudBrainTools } from '~/pages/cloudbrain/tools';
import { CLUSTERS } from '~/const';
import { timeSinceUnix, getListValueWithKey } from '~/utils';
import { getAiTaskList, getAiTaskDebugUrl, stopAiTask, deleteAiTask } from '~/apis/modules/cloudbrain';

import relativeTime from 'dayjs/plugin/relativeTime';
import localizedFormat from 'dayjs/plugin/localizedFormat';
import 'dayjs/locale/zh-cn';
import 'dayjs/locale/en';
import dayjs from 'dayjs';
import { lang } from '~/langs';

dayjs.locale(lang == 'zh-CN' ? 'zh-cn' : 'en');
dayjs.extend(relativeTime);
dayjs.extend(localizedFormat);

const cloudBrainTools = new CloudBrainTools();

export default {
data() {
return {
curTab: 'task',
tabs: [...TABS],
repoOwnerName: location.pathname.split('/')[1],
repoName: location.pathname.split('/')[2],
isRepoEmpty: false,
sort: '',
pageCfg: { ...ListPageConfigs },
tableData: [],
page: 1,
pageSizes: [10],
pageSize: 10,
total: 0,
canCreateTask: false,
loading: false,
errorMsgBoxShow: false,
errorMsg: '',
maskLoading: false,
maskLoadingContent: '',
operating: false,
taskAlreadyDialogShow: false,
};
},
components: { LoadingMask },
methods: {
getTableData() {
this.loading = true;
getAiTaskList({
repoOwnerName: this.repoOwnerName,
repoName: this.repoName,
page: this.page,
page_size: this.pageSize,
job_type: this.pageCfg.page.jobType,
compute_source: this.sort,
}).then(res => {
this.loading = false;
res = res.data;
if (res.code == 0) {
const data = res.data;
this.canCreateTask = data.can_create_task;
this.isRepoEmpty = data.is_repo_empty;
this.total = data.total;
data.tasks.forEach(item => {
const obj = Object.assign({}, item);
delete obj.task;
const task = item.task;
Object.assign(task, obj);
task.computeSourceShow = task.compute_source == 'GPU' ? 'CPU/GPU' : task.compute_source;
task.clusterName = getListValueWithKey(CLUSTERS, task.cluster);
task.repoOwnerName = this.repoOwnerName;
task.repoName = this.repoName;
task.jobLink = `/${this.repoOwnerName}/${this.repoName}/${getAiJobLink(task)}`;
task.createdFromNow = this.calcFromNow(task.created_unix);
cloudBrainTools.checkOperation(task);
});
this.tableData = data.tasks || [];
cloudBrainTools.initRefreshData(this.tableData);
}
}).catch(err => {
this.loading = false;
console.log(err);
});
},
changeSort() {
this.page = 1;
this.getTableData();
},
currentChange(page) {
this.page = page;
this.getTableData();
},
sizeChange(pageSize) {
this.page = 1;
this.pageSize = pageSize;
this.getTableData();
},
calcFromNow(unix) {
return timeSinceUnix(unix, Date.now() / 1000);
},
dateFormat(unix) {
return lang == 'zh-CN' ? dayjs(unix * 1000).format('YYYY年MM月DD日 HH时mm分ss秒') :
dayjs(unix * 1000).format('ddd, D MMM YYYY HH:mm:ss [CST]');
},
// operations
opDebug(row) {
if (this.operating) return;
this.operating = true;
getAiTaskDebugUrl({
repoOwnerName: row.task.repoOwnerName,
repoName: row.task.repoName,
id: row.task.id,
}).then(res => {
this.operating = false;
res = res.data;
if (res.code == 0) {
if (res.data && res.data.url) {
window.open(res.data.url)
}
} else {
this.$message({
type: 'error',
message: res.msg,
});
}
}).catch(err => {
this.operating = false;
console.log(err);
});
},
opStop(row) {
if (this.operating) return;
this.operating = true;
stopAiTask({
repoOwnerName: row.task.repoOwnerName,
repoName: row.task.repoName,
id: row.task.id,
}).then(res => {
this.operating = false;
res = res.data;
if (res.code == 0) {
const data = res.data;
Object.assign(row.task, data);
row.task.createdFromNow = this.calcFromNow(row.task.created_unix);
cloudBrainTools.checkOperation(row.task);
} else {
this.$message({
type: 'error',
message: res.msg
});
}
}).catch(err => {
this.operating = false;
});
},
opDelete(row) {
if (this.operating) return;
this.$confirm(this.$t('cloudbrainObj.deleteConfirmTips'), this.$t('tips'), {
confirmButtonText: this.$t('confirm'),
cancelButtonText: this.$t('cancel'),
type: 'warning'
}).then(() => {
this.operating = true;
this.maskLoading = true;
this.maskLoadingContent = this.$t('cloudbrainObj.deletingTips');
deleteAiTask({
repoOwnerName: row.task.repoOwnerName,
repoName: row.task.repoName,
id: row.task.id,
}).then(res => {
this.operating = false;
this.maskLoading = false;
if (this.total % this.pageSize == 1 && this.page > 1) {
this.page -= 1;
}
this.getTableData();
}).catch(err => {
this.maskLoading = false;
this.operating = false;
this.$message({
type: 'error',
message: this.$t('operationFailed'),
});
});
}).catch(() => {
this.$message({
type: 'info',
message: this.$t('cancelOperate'),
});
});
},
},
beforeMount() {
// const urlParams = getUrlSearchParams();
// const configs = getListPageConfigs(location.href) || {};
// this.pageCfg = configs;
this.getTableData();
},
mounted() { },
beforeDestroy() { },
};
</script>

<style scoped lang="less">
@import '~/components/cloudbrain/cloudbrain.less';

.container {
min-height: 350px;
}

.header {
margin-bottom: 26px;
display: flex;
align-items: center;
justify-content: space-between;

.tab-c {
display: flex;
align-items: center;

.tab-item {
display: flex;
align-items: center;
justify-content: center;
font-size: 13px;
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;

&.focus {
color: #0087f5;
border-color: #0087f5;
border-left: 1px solid #0087f5;
}

&:first-child {
border-radius: 0.28571429rem 0 0 0.28571429rem;
border-left: 1px solid rgba(34, 36, 38, .15);

&.focus {
border-color: #0087f5;
}
}

&:last-child {
border-radius: 0 0.28571429rem 0.28571429rem 0;
}

&:hover:not(.focus) {
background: rgba(0, 0, 0, .03);
}
}
}

.right-c {
display: flex;
align-items: center;
}
}

.table-container {
/deep/ .el-table__body {
td {
height: 64px;
}
}

.dispaly-job-name {
font-size: 14px;
// padding-left: 10px;
font-weight: bold;
}

.status-wrap {
display: flex;
align-items: center;

i {
margin-right: 4px;
}
}

.creator-wrap {
display: flex;
align-items: center;
justify-content: center;

img {
height: 28px;
width: 28px;
border-radius: 100%;
}
}

.op-wrap {
display: flex;
align-items: center;
justify-content: center;

a {
margin: 0 10px;
font-size: 14px;
color: #1678c2;

&.disabled {
color: rgba(0, 0, 0, .87);
}
}

.el-dropdown {
margin: 0 10px;
color: rgba(0, 0, 0, .87);
cursor: pointer;
}
}
}

.list-foot {
text-align: center;
margin-top: 12px;
}

.foot-tips {
margin-top: 2rem;
color: #888888;
font-size: 14px;

/deep/ span {
color: #f2711c;
}
}

/deep/ .el-dropdown-menu__item {
a {
color: #1678c2;
}

&.is-disabled {
color: rgba(0, 0, 0, .87);
pointer-events: none;
opacity: 0.45 !important;

a {
color: rgba(0, 0, 0, .87);
pointer-events: none;
opacity: 0.45 !important;
}
}
}

.empty-page {
display: flex;
flex-direction: column;
align-items: center;

.empty-icon {
height: 100px;
width: 100px;
background: url(/img/empty-box.svg) center center no-repeat;
margin: 2rem 0 1rem;
scale: 0.8;
}

.empty-title {
text-align: center;
color: #3f3f40;
font-size: 18px;
margin-bottom: 1rem;
}

.empty-content {
margin: 2rem 0 0;

div {
font-size: 14px;
color: #a6a6a6;
line-height: 22px;
margin-bottom: 4px;
}
}
}

.task-already-dlg {
margin-top: 15vh;

/deep/.el-dialog__header {
display: none;
}

/deep/.el-dialog__body {
padding: 0px 0px;
}
}

.err-msg-box-already {
padding: 1em 1.5em;
background-color: rgba(242, 113, 28, 0.05);
border: 2px solid rgba(242, 113, 28, 1);
border-radius: 5px;

.msg-content {
display: flex;
align-items: center;

i {
font-size: 35px;
color: rgba(242, 113, 28, 1);
}

.msg-content-tip {
text-align: left;
margin-left: 1rem;

.line-1 {
font-weight: 600;
line-height: 2;

span {
color: rgba(242, 113, 28, 1);
}
}

.line-2 {
color: #939393
}
}
}
}
</style>

+ 17
- 0
web_src/vuepages/pages/supercompute/list/vp-cloudbrain-super-list.js View File

@@ -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');

+ 6
- 4
web_src/vuepages/utils/index.js View File

@@ -34,10 +34,11 @@ export const transFileSize = (srcSize) => {
export const renderSpecStr = (spec, showPoint) => {
if (!spec) return '';
var ngpu = `${spec.ComputeResource}: ${spec.AccCardsNum + '*' + getListValueWithKey(ACC_CARD_TYPE, spec.AccCardType)}`;
var gpuMemStr = spec.GPUMemGiB != 0 ? `${i18n.t('resourcesManagement.gpuMem')}: ${spec.GPUMemGiB}GB, ` : '';
var gpuMemStr = spec.GPUMemGiB != 0 ? `, ${i18n.t('resourcesManagement.gpuMem')}: ${spec.GPUMemGiB}GB, ` : '';
var memStr = spec.MemGiB != 0 ? `, ${i18n.t('resourcesManagement.mem')}: ${spec.MemGiB}GB` : '';
var sharedMemStr = spec.ShareMemGiB != 0 ? `, ${i18n.t('resourcesManagement.shareMem')}: ${spec.ShareMemGiB}GB` : '';
var pointStr = showPoint ? `, ${spec.UnitPrice == 0 ? i18n.t('resourcesManagement.free') : spec.UnitPrice + i18n.t('resourcesManagement.point_hr')}` : '';
var specStr = `${ngpu}, CPU: ${spec.CpuCores}, ${gpuMemStr}${i18n.t('resourcesManagement.mem')}: ${spec.MemGiB}GB${sharedMemStr}${pointStr}`;
var specStr = `${ngpu}, CPU: ${spec.CpuCores}${gpuMemStr}${memStr}${sharedMemStr}${pointStr}`;
return specStr;
};

@@ -50,10 +51,11 @@ export const renderSpecObject = (spec, showPoint) => {
};
}
var ngpu = `${spec.compute_resource}: ${spec.acc_cards_num + '*' + getListValueWithKey(ACC_CARD_TYPE, spec.acc_card_type)}`;
var gpuMemStr = spec.gpu_mem_gi_b != 0 ? `${i18n.t('resourcesManagement.gpuMem')}: ${spec.gpu_mem_gi_b}GB, ` : '';
var gpuMemStr = spec.gpu_mem_gi_b != 0 ? `, ${i18n.t('resourcesManagement.gpuMem')}: ${spec.gpu_mem_gi_b}GB` : '';
var memStr = spec.mem_gi_b != 0 ? `, ${i18n.t('resourcesManagement.mem')}: ${spec.mem_gi_b}GB` : '';
var sharedMemStr = spec.share_mem_gi_b != 0 ? `, ${i18n.t('resourcesManagement.shareMem')}: ${spec.share_mem_gi_b}GB` : '';
var pointStr = showPoint ? `${spec.unit_price == 0 ? i18n.t('resourcesManagement.free') : spec.unit_price + i18n.t('resourcesManagement.point_hr')}` : '';
var specStr = `${ngpu}, CPU: ${spec.cpu_cores}, ${gpuMemStr}${i18n.t('resourcesManagement.mem')}: ${spec.mem_gi_b}GB${sharedMemStr}`;
var specStr = `${ngpu}, CPU: ${spec.cpu_cores}${gpuMemStr}${memStr}${sharedMemStr}`;
return {
...spec,
id: spec.id.toString(),


Loading…
Cancel
Save