Browse Source

Merge remote-tracking branch 'origin/res-manage-v2' into point-v2

# Conflicts:
#	models/cloudbrain.go
#	options/locale/locale_en-US.ini
#	routers/repo/cloudbrain.go
#	routers/repo/modelarts.go
#	templates/repo/cloudbrain/benchmark/new.tmpl
#	templates/repo/cloudbrain/inference/new.tmpl
#	templates/repo/cloudbrain/new.tmpl
#	templates/repo/cloudbrain/trainjob/new.tmpl
#	templates/repo/grampus/trainjob/gpu/new.tmpl
#	templates/repo/grampus/trainjob/npu/new.tmpl
#	templates/repo/modelarts/inferencejob/new.tmpl
#	templates/repo/modelarts/notebook/new.tmpl
#	templates/repo/modelarts/trainjob/new.tmpl
#	templates/repo/modelarts/trainjob/version_new.tmpl
#	web_src/js/standalone/specsuse.js
tags/v1.22.9.2^2
chenyifan01 3 years ago
parent
commit
b0a12f43f0
57 changed files with 1589 additions and 358 deletions
  1. +72
    -28
      models/cloudbrain.go
  2. +6
    -12
      models/dataset.go
  3. +14
    -0
      models/repo_collaboration.go
  4. +2
    -0
      models/resource_queue.go
  5. +1
    -0
      models/resource_specification.go
  6. +3
    -3
      modules/cloudbrain/cloudbrain.go
  7. +2
    -2
      modules/grampus/grampus.go
  8. +26
    -10
      modules/modelarts/modelarts.go
  9. +215
    -0
      modules/modelarts_cd/modelarts.go
  10. +220
    -0
      modules/modelarts_cd/resty.go
  11. +42
    -0
      modules/modelarts_gateway/core/escape.go
  12. +208
    -0
      modules/modelarts_gateway/core/signer.go
  13. +75
    -7
      modules/setting/setting.go
  14. +13
    -7
      options/locale/locale_en-US.ini
  15. +9
    -2
      options/locale/locale_zh-CN.ini
  16. +2
    -2
      routers/admin/cloudbrains.go
  17. +139
    -30
      routers/api/v1/repo/cloudbrain.go
  18. +12
    -7
      routers/repo/cloudbrain.go
  19. +2
    -7
      routers/repo/dataset.go
  20. +1
    -1
      routers/repo/grampus.go
  21. +194
    -95
      routers/repo/modelarts.go
  22. +1
    -3
      routers/user/home.go
  23. +13
    -2
      services/cloudbrain/resource/resource_specification.go
  24. +12
    -4
      templates/admin/cloudbrain/list.tmpl
  25. +1
    -1
      templates/custom/wait_count_train.tmpl
  26. +11
    -4
      templates/repo/cloudbrain/benchmark/new.tmpl
  27. +39
    -15
      templates/repo/cloudbrain/benchmark/show.tmpl
  28. +9
    -1
      templates/repo/cloudbrain/inference/new.tmpl
  29. +49
    -5
      templates/repo/cloudbrain/inference/show.tmpl
  30. +23
    -15
      templates/repo/cloudbrain/new.tmpl
  31. +7
    -1
      templates/repo/cloudbrain/show.tmpl
  32. +8
    -1
      templates/repo/cloudbrain/trainjob/new.tmpl
  33. +8
    -2
      templates/repo/cloudbrain/trainjob/show.tmpl
  34. +9
    -2
      templates/repo/grampus/trainjob/gpu/new.tmpl
  35. +8
    -1
      templates/repo/grampus/trainjob/npu/new.tmpl
  36. +7
    -2
      templates/repo/grampus/trainjob/show.tmpl
  37. +9
    -1
      templates/repo/modelarts/inferencejob/new.tmpl
  38. +8
    -1
      templates/repo/modelarts/inferencejob/show.tmpl
  39. +14
    -5
      templates/repo/modelarts/notebook/new.tmpl
  40. +8
    -1
      templates/repo/modelarts/notebook/show.tmpl
  41. +26
    -3
      templates/repo/modelarts/trainjob/new.tmpl
  42. +8
    -2
      templates/repo/modelarts/trainjob/show.tmpl
  43. +11
    -51
      templates/repo/modelarts/trainjob/version_new.tmpl
  44. +2
    -2
      templates/repo/modelmanage/convertIndex.tmpl
  45. +3
    -3
      templates/repo/modelmanage/index.tmpl
  46. +1
    -1
      templates/repo/modelmanage/showinfo.tmpl
  47. +12
    -5
      templates/user/dashboard/cloudbrains.tmpl
  48. +2
    -1
      web_src/js/components/Model.vue
  49. +1
    -1
      web_src/js/components/dataset/referenceDataset.vue
  50. +5
    -2
      web_src/js/components/dataset/selectDataset.vue
  51. +5
    -1
      web_src/js/features/i18nVue.js
  52. +2
    -0
      web_src/js/standalone/specsuse.js
  53. +1
    -1
      web_src/vuepages/const/index.js
  54. +2
    -1
      web_src/vuepages/langs/config/en-US.js
  55. +2
    -1
      web_src/vuepages/langs/config/zh-CN.js
  56. +3
    -2
      web_src/vuepages/pages/resources/components/QueueDialog.vue
  57. +1
    -1
      web_src/vuepages/pages/resources/components/SceneDialog.vue

+ 72
- 28
models/cloudbrain.go View File

@@ -25,7 +25,8 @@ type ModelArtsJobStatus string
const (
TypeCloudBrainOne int = iota
TypeCloudBrainTwo
TypeC2Net //智算网络
TypeC2Net //智算网络
TypeCDCenter //成都智算中心

TypeCloudBrainAll = -1
)
@@ -71,6 +72,7 @@ const (
ModelArtsStopping ModelArtsJobStatus = "STOPPING" //停止中
ModelArtsStopped ModelArtsJobStatus = "STOPPED" //停止
ModelArtsUnavailable ModelArtsJobStatus = "UNAVAILABLE" //故障
ModelArtsDeleting ModelArtsJobStatus = "DELETING" //删除中
ModelArtsDeleted ModelArtsJobStatus = "DELETED" //已删除
ModelArtsResizing ModelArtsJobStatus = "RESIZING" //规格变更中
ModelArtsResizFailed ModelArtsJobStatus = "RESIZE_FAILED" //规格变更失败
@@ -119,6 +121,7 @@ const (
//AI center
AICenterOfCloudBrainOne = "OpenIOne"
AICenterOfCloudBrainTwo = "OpenITwo"
AICenterOfChengdu = "OpenIChengdu"

//ComputeResource
GPU = "GPU"
@@ -655,23 +658,13 @@ type SpecialPools struct {
Pools []*SpecialPool `json:"pools"`
}
type SpecialPool struct {
Org string `json:"org"`
Type string `json:"type"`
IsExclusive bool `json:"isExclusive"`
Pool []*GpuInfo `json:"pool"`
JobType []string `json:"jobType"`
ResourceSpec []*ResourceSpec `json:"resourceSpecs"`
Flavor []*FlavorInfo `json:"flavor"`
}

type ImageInfosModelArts struct {
ImageInfo []*ImageInfoModelArts `json:"image_info"`
}

type ImageInfoModelArts struct {
Id string `json:"id"`
Value string `json:"value"`
Desc string `json:"desc"`
Org string `json:"org"`
Type string `json:"type"`
IsExclusive bool `json:"isExclusive"`
Pool []*GpuInfo `json:"pool"`
JobType []string `json:"jobType"`
ResourceSpec []*ResourceSpec `json:"resourceSpecs"`
Flavor []*setting.FlavorInfo `json:"flavor"`
}

type PoolInfos struct {
@@ -777,6 +770,17 @@ type CreateNotebook2Params struct {
Volume VolumeReq `json:"volume"`
}

type CreateNotebookWithoutPoolParams struct {
JobName string `json:"name"`
Description string `json:"description"`
Duration int64 `json:"duration"` //ms
Feature string `json:"feature"`
Flavor string `json:"flavor"`
ImageID string `json:"image_id"`
WorkspaceID string `json:"workspace_id"`
Volume VolumeReq `json:"volume"`
}

type VolumeReq struct {
Capacity int `json:"capacity"`
Category string `json:"category"`
@@ -1000,6 +1004,7 @@ type NotebookGetJobTokenResult struct {
}

type NotebookDelResult struct {
NotebookResult
InstanceID string `json:"instance_id"`
}

@@ -1138,6 +1143,7 @@ type DatasetDownload struct {
DatasetName string `json:"dataset_name"`
DatasetDownloadLink string `json:"dataset_download_link"`
RepositoryLink string `json:"repository_link"`
IsDelete bool `json:"is_delete"`
}

type DataSource struct {
@@ -1525,12 +1531,6 @@ func Cloudbrains(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, error) {
)
}

if len(opts.ComputeResource) > 0 {
cond = cond.And(
builder.Eq{"cloudbrain.compute_resource": opts.ComputeResource},
)
}

if len(opts.JobTypes) > 0 {
if opts.JobTypeNot {
cond = cond.And(
@@ -1550,7 +1550,7 @@ func Cloudbrains(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, error) {
if (opts.Cluster) != "" {
if opts.Cluster == "resource_cluster_openi" {
cond = cond.And(
builder.Or(builder.Eq{"cloudbrain.type": TypeCloudBrainOne}, builder.Eq{"cloudbrain.type": TypeCloudBrainTwo}),
builder.Or(builder.Eq{"cloudbrain.type": TypeCloudBrainOne}, builder.Eq{"cloudbrain.type": TypeCloudBrainTwo}, builder.Eq{"cloudbrain.type": TypeCDCenter}),
)
}
if opts.Cluster == "resource_cluster_c2net" {
@@ -1992,9 +1992,9 @@ func GetCloudbrainCountByUserID(userID int64, jobType string) (int, error) {

func GetCloudbrainRunCountByRepoID(repoID int64) (int, error) {
count, err := x.In("status", JobWaiting, JobRunning, ModelArtsCreateQueue, ModelArtsCreating, ModelArtsStarting,
ModelArtsReadyToStart, ModelArtsResizing, ModelArtsStartQueuing, ModelArtsRunning, ModelArtsRestarting, ModelArtsTrainJobInit,
ModelArtsReadyToStart, ModelArtsResizing, ModelArtsStartQueuing, ModelArtsRunning, ModelArtsDeleting, ModelArtsRestarting, ModelArtsTrainJobInit,
ModelArtsTrainJobImageCreating, ModelArtsTrainJobSubmitTrying, ModelArtsTrainJobWaiting, ModelArtsTrainJobRunning, ModelArtsStopping, ModelArtsResizing,
ModelArtsTrainJobScaling, ModelArtsTrainJobCheckInit, ModelArtsTrainJobCheckRunning, ModelArtsTrainJobCheckRunningCompleted).And("repo_id = ?", repoID).Count(new(Cloudbrain))
ModelArtsTrainJobScaling, ModelArtsTrainJobCheckInit, ModelArtsTrainJobCheckRunning, ModelArtsTrainJobKilling, ModelArtsTrainJobCheckRunningCompleted).And("repo_id = ?", repoID).Count(new(Cloudbrain))
return int(count), err
}

@@ -2016,7 +2016,7 @@ func GetWaitingCloudbrainCount(cloudbrainType int, computeResource string, jobTy

func GetCloudbrainNotebookCountByUserID(userID int64) (int, error) {
count, err := x.In("status", ModelArtsCreateQueue, ModelArtsCreating, ModelArtsStarting, ModelArtsReadyToStart, ModelArtsResizing, ModelArtsStartQueuing, ModelArtsRunning, ModelArtsRestarting).
And("job_type = ? and user_id = ? and type = ?", JobTypeDebug, userID, TypeCloudBrainTwo).Count(new(Cloudbrain))
And("job_type = ? and user_id = ? and type in (?,?)", JobTypeDebug, userID, TypeCloudBrainTwo, TypeCDCenter).Count(new(Cloudbrain))
return int(count), err
}

@@ -2494,3 +2494,47 @@ func GetCloudbrainCountByJobName(jobName, jobType string, typeCloudbrain int) (i
count, err := x.Where("job_name = ? and job_type= ? and type = ?", jobName, jobType, typeCloudbrain).Count(new(Cloudbrain))
return int(count), err
}

func LoadSpecs(tasks []*Cloudbrain) error {
cloudbrainIds := make([]int64, len(tasks))
for i, v := range tasks {
cloudbrainIds[i] = v.ID
}
specs := make([]*CloudbrainSpec, 0)
err := x.In("cloudbrain_id", cloudbrainIds).Find(&specs)
if err != nil {
return err
}
specMap := make(map[int64]*CloudbrainSpec)
for _, v := range specs {
specMap[v.SpecId] = v
}
for _, v := range tasks {
if specMap[v.ID] != nil {
v.Spec = specMap[v.ID].ConvertToSpecification()
}
}
return nil
}

func LoadSpecs4CloudbrainInfo(tasks []*CloudbrainInfo) error {
cloudbrainIds := make([]int64, len(tasks))
for i, v := range tasks {
cloudbrainIds[i] = v.Cloudbrain.ID
}
specs := make([]*CloudbrainSpec, 0)
err := x.In("cloudbrain_id", cloudbrainIds).Find(&specs)
if err != nil {
return err
}
specMap := make(map[int64]*CloudbrainSpec)
for _, v := range specs {
specMap[v.CloudbrainID] = v
}
for _, v := range tasks {
if specMap[v.Cloudbrain.ID] != nil {
v.Cloudbrain.Spec = specMap[v.Cloudbrain.ID].ConvertToSpecification()
}
}
return nil
}

+ 6
- 12
models/dataset.go View File

@@ -121,22 +121,20 @@ func (datasets DatasetList) loadAttachmentAttributes(opts *SearchDatasetOptions)

for i := range datasets {
if attachment.DatasetID == datasets[i].ID {
if opts.StarByMe {

if !attachment.IsPrivate{
datasets[i].Attachments = append(datasets[i].Attachments, attachment)
}else{
permission, ok := permissionMap[datasets[i].ID]
if !ok {

permission = false
datasets[i].Repo.GetOwner()
if datasets[i].Repo.Owner.IsOrganization() {
if datasets[i].Repo.Owner.IsUserPartOfOrg(opts.User.ID) {
log.Info("user is member of org.")
permission = true
}
}
if !permission {
isCollaborator, _ := datasets[i].Repo.IsCollaborator(opts.User.ID)
if isCollaborator {
isInRepoTeam,_:=datasets[i].Repo.IsInRepoTeam(opts.User.ID)

if isCollaborator ||isInRepoTeam {
log.Info("Collaborator user may visit the attach.")
permission = true
}
@@ -147,11 +145,7 @@ func (datasets DatasetList) loadAttachmentAttributes(opts *SearchDatasetOptions)

if permission {
datasets[i].Attachments = append(datasets[i].Attachments, attachment)
} else if !attachment.IsPrivate {
datasets[i].Attachments = append(datasets[i].Attachments, attachment)
}
} else {
datasets[i].Attachments = append(datasets[i].Attachments, attachment)
}

}


+ 14
- 0
models/repo_collaboration.go View File

@@ -130,6 +130,20 @@ func (repo *Repository) IsCollaborator(userID int64) (bool, error) {
return repo.isCollaborator(x, userID)
}

func (repo *Repository) IsInRepoTeam(userID int64) (bool, error) {
teams,err:=repo.GetRepoTeams()
if err!=nil || len(teams)==0{
return false,err
}
for _,team :=range teams{
if team.IsMember(userID){
return true,nil
}
}
return false,nil

}

func (repo *Repository) changeCollaborationAccessMode(e Engine, uid int64, mode AccessMode) error {
// Discard invalid input
if mode <= AccessModeNone || mode > AccessModeOwner {


+ 2
- 0
models/resource_queue.go View File

@@ -71,6 +71,8 @@ func (r ResourceQueueReq) ToDTO() ResourceQueue {
q.AiCenterName = "云脑一"
} else if r.AiCenterCode == AICenterOfCloudBrainTwo {
q.AiCenterName = "云脑二"
} else if r.AiCenterCode == AICenterOfChengdu {
q.AiCenterName = "启智成都智算"
}
}
return q


+ 1
- 0
models/resource_specification.go View File

@@ -525,6 +525,7 @@ func InitCloudbrainTwoSpecs() (map[string]*Specification, error) {
MemGiB: float32(i * 256),
GPUMemGiB: float32(32),
Status: SpecOffShelf,
IsAvailable: true,
}
_, err = x.Insert(spec)
if err != nil {


+ 3
- 3
modules/cloudbrain/cloudbrain.go View File

@@ -20,7 +20,7 @@ import (
const (
//Command = `pip3 install jupyterlab==2.2.5 -i https://pypi.tuna.tsinghua.edu.cn/simple;service ssh stop;jupyter lab --no-browser --ip=0.0.0.0 --allow-root --notebook-dir="/code" --port=80 --LabApp.token="" --LabApp.allow_origin="self https://cloudbrain.pcl.ac.cn"`
//CommandBenchmark = `echo "start benchmark";python /code/test.py;echo "end benchmark"`
CommandBenchmark = `echo "start benchmark";cd /benchmark && bash run_bk.sh;echo "end benchmark"`
CommandBenchmark = `echo "start benchmark";cd /benchmark && bash run_bk.sh | tee /model/benchmark-log.txt;echo "end benchmark"`
CodeMountPath = "/code"
DataSetMountPath = "/dataset"
ModelMountPath = "/model"
@@ -30,8 +30,8 @@ const (
Snn4imagenetMountPath = "/snn4imagenet"
BrainScoreMountPath = "/brainscore"
TaskInfoName = "/taskInfo"
Snn4imagenetCommand = `/opt/conda/bin/python /snn4imagenet/testSNN_script.py --modelname '%s' --modelpath '/dataset' --modeldescription '%s'`
BrainScoreCommand = `bash /brainscore/brainscore_test_par4shSrcipt.sh -b '%s' -n '%s' -p '/dataset' -d '%s'`
Snn4imagenetCommand = `/opt/conda/bin/python /snn4imagenet/testSNN_script.py --modelname '%s' --modelpath '/dataset' --modeldescription '%s' | tee /model/benchmark-log.txt`
BrainScoreCommand = `bash /brainscore/brainscore_test_par4shSrcipt.sh -b '%s' -n '%s' -p '/dataset' -d '%s' | tee /model/benchmark-log.txt`

SubTaskName = "task1"



+ 2
- 2
modules/grampus/grampus.go View File

@@ -30,8 +30,8 @@ const (

var (
poolInfos *models.PoolInfos
FlavorInfos *models.FlavorInfos
ImageInfos *models.ImageInfosModelArts
FlavorInfos *setting.StFlavorInfos
ImageInfos *setting.StImageInfosModelArts

SpecialPools *models.SpecialPools
)


+ 26
- 10
modules/modelarts/modelarts.go View File

@@ -1,6 +1,7 @@
package modelarts

import (
"code.gitea.io/gitea/modules/modelarts_cd"
"encoding/json"
"errors"
"fmt"
@@ -68,10 +69,9 @@ const (

var (
poolInfos *models.PoolInfos
FlavorInfos *models.FlavorInfos
ImageInfos *models.ImageInfosModelArts
TrainFlavorInfos *Flavor
SpecialPools *models.SpecialPools
SpecialPools *models.SpecialPools
MultiNodeConfig *MultiNodes
)

type GenerateTrainJobReq struct {
@@ -168,6 +168,14 @@ type ResourcePool struct {
} `json:"resource_pool"`
}

type MultiNodes struct{
Info []OrgMultiNode `json:"multinode"`
}
type OrgMultiNode struct{
Org string `json:"org"`
Node []int `json:"node"`
}

// type Parameter struct {
// Label string `json:"label"`
// Value string `json:"value"`
@@ -754,11 +762,7 @@ func GetNotebookImageName(imageId string) (string, error) {
var validImage = false
var imageName = ""

if ImageInfos == nil {
json.Unmarshal([]byte(setting.ImageInfos), &ImageInfos)
}

for _, imageInfo := range ImageInfos.ImageInfo {
for _, imageInfo := range setting.StImageInfos.ImageInfo {
if imageInfo.Id == imageId {
validImage = true
imageName = imageInfo.Value
@@ -779,6 +783,13 @@ func InitSpecialPool() {
}
}

func InitMultiNode(){
if MultiNodeConfig ==nil && setting.ModelArtsMultiNode!=""{
json.Unmarshal([]byte(setting.ModelArtsMultiNode), &MultiNodeConfig)
}

}

func HandleTrainJobInfo(task *models.Cloudbrain) error {

result, err := GetTrainJob(task.JobID, strconv.FormatInt(task.VersionID, 10))
@@ -815,8 +826,13 @@ func HandleTrainJobInfo(task *models.Cloudbrain) error {
}

func HandleNotebookInfo(task *models.Cloudbrain) error {

result, err := GetNotebook2(task.JobID)
var result *models.GetNotebook2Result
var err error
if task.Type == models.TypeCloudBrainTwo {
result, err = GetNotebook2(task.JobID)
} else if task.Type == models.TypeCDCenter {
result, err = modelarts_cd.GetNotebook(task.JobID)
}
if err != nil {
log.Error("GetNotebook2(%s) failed:%v", task.DisplayJobName, err)
return err


+ 215
- 0
modules/modelarts_cd/modelarts.go View File

@@ -0,0 +1,215 @@
package modelarts_cd

import (
"errors"
"strconv"
"strings"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/notification"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
)

const (
//notebook
storageTypeOBS = "obs"
autoStopDuration = 4 * 60 * 60
autoStopDurationMs = 4 * 60 * 60 * 1000
MORDELART_USER_IMAGE_ENGINE_ID = -1
DataSetMountPath = "/home/ma-user/work"
NotebookEnv = "Python3"
NotebookType = "Ascend"
FlavorInfo = "Ascend: 1*Ascend 910 CPU: 24 核 96GiB (modelarts.kat1.xlarge)"

//train-job
CodePath = "/code/"
OutputPath = "/output/"
ResultPath = "/result/"
LogPath = "/log/"
JobPath = "/job/"
OrderDesc = "desc" //向下查询
OrderAsc = "asc" //向上查询
Lines = 500
TrainUrl = "train_url"
DataUrl = "data_url"
MultiDataUrl = "multi_data_url"
ResultUrl = "result_url"
CkptUrl = "ckpt_url"
DeviceTarget = "device_target"
Ascend = "Ascend"
PerPage = 10
IsLatestVersion = "1"
NotLatestVersion = "0"
VersionCountOne = 1

SortByCreateTime = "create_time"
ConfigTypeCustom = "custom"
TotalVersionCount = 1
)

var ()

type VersionInfo struct {
Version []struct {
ID int `json:"id"`
Value string `json:"value"`
Url string `json:"url"`
} `json:"version"`
}

type Flavor struct {
Info []struct {
Code string `json:"code"`
Value string `json:"value"`
} `json:"flavor"`
}

type Engine struct {
Info []struct {
ID int `json:"id"`
Value string `json:"value"`
} `json:"engine"`
}

type ResourcePool struct {
Info []struct {
ID string `json:"id"`
Value string `json:"value"`
} `json:"resource_pool"`
}

type Parameters struct {
Parameter []struct {
Label string `json:"label"`
Value string `json:"value"`
} `json:"parameter"`
}

func GenerateNotebook(ctx *context.Context, displayJobName, jobName, uuid, description, imageId string, spec *models.Specification) error {
imageName, err := GetNotebookImageName(imageId)
if err != nil {
log.Error("GetNotebookImageName failed: %v", err.Error())
return err
}
createTime := timeutil.TimeStampNow()
jobResult, err := createNotebook(models.CreateNotebookWithoutPoolParams{
JobName: jobName,
Description: description,
Flavor: spec.SourceSpecId,
Duration: autoStopDurationMs,
ImageID: imageId,
Feature: models.NotebookFeature,
Volume: models.VolumeReq{
Capacity: setting.Capacity,
Category: models.EVSCategory,
Ownership: models.ManagedOwnership,
},
WorkspaceID: "0",
})
if err != nil {
log.Error("createNotebook failed: %v", err.Error())
if strings.HasPrefix(err.Error(), UnknownErrorPrefix) {
log.Info("(%s)unknown error, set temp status", displayJobName)
errTemp := models.InsertCloudbrainTemp(&models.CloudbrainTemp{
JobID: models.TempJobId,
VersionID: models.TempVersionId,
Status: models.TempJobStatus,
Type: models.TypeCDCenter,
JobName: jobName,
JobType: string(models.JobTypeDebug),
})
if errTemp != nil {
log.Error("InsertCloudbrainTemp failed: %v", errTemp.Error())
return errTemp
}
}
return err
}
task := &models.Cloudbrain{
Status: jobResult.Status,
UserID: ctx.User.ID,
RepoID: ctx.Repo.Repository.ID,
JobID: jobResult.ID,
JobName: jobName,
FlavorCode: spec.SourceSpecId,
DisplayJobName: displayJobName,
JobType: string(models.JobTypeDebug),
Type: models.TypeCDCenter,
Uuid: uuid,
ComputeResource: models.NPUResource,
Image: imageName,
Description: description,
CreatedUnix: createTime,
UpdatedUnix: createTime,
Spec: spec,
}

err = models.CreateCloudbrain(task)
if err != nil {
return err
}

stringId := strconv.FormatInt(task.ID, 10)
notification.NotifyOtherTask(ctx.User, ctx.Repo.Repository, stringId, displayJobName, models.ActionCreateDebugNPUTask)
return nil
}

func GetNotebookImageName(imageId string) (string, error) {
var validImage = false
var imageName = ""

for _, imageInfo := range setting.StImageInfos.ImageInfo {
if imageInfo.Id == imageId {
validImage = true
imageName = imageInfo.Value
}
}

if !validImage {
log.Error("the image id(%s) is invalid", imageId)
return imageName, errors.New("the image id is invalid")
}

return imageName, nil
}

/*
func HandleNotebookInfo(task *models.Cloudbrain) error {

result, err := GetNotebook(task.JobID)
if err != nil {
log.Error("GetNotebook2(%s) failed:%v", task.DisplayJobName, err)
return err
}

if result != nil {
oldStatus := task.Status
task.Status = result.Status
if task.StartTime == 0 && result.Lease.UpdateTime > 0 {
task.StartTime = timeutil.TimeStamp(result.Lease.UpdateTime / 1000)
}
if task.EndTime == 0 && models.IsModelArtsDebugJobTerminal(task.Status) {
task.EndTime = timeutil.TimeStampNow()
}
task.CorrectCreateUnix()
task.ComputeAndSetDuration()
if oldStatus != task.Status {
notification.NotifyChangeCloudbrainStatus(task, oldStatus)
}
if task.FlavorCode == "" {
task.FlavorCode = result.Flavor
}
err = models.UpdateJob(task)
if err != nil {
log.Error("UpdateJob(%s) failed:%v", task.DisplayJobName, err)
return err
}
}

return nil
}

*/

+ 220
- 0
modules/modelarts_cd/resty.go View File

@@ -0,0 +1,220 @@
package modelarts_cd

import (
"bytes"
"code.gitea.io/gitea/modules/modelarts_gateway/core"
"crypto/tls"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"strconv"
"time"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
)

var (
httpClient *http.Client
HOST string
TOKEN string
)

const (
errorCodeExceedLimit = "ModelArts.0118"

//notebook 2.0
urlNotebook2 = "/notebooks"

//error code
modelartsIllegalToken = "ModelArts.6401"
NotebookNotFound = "ModelArts.6404"
NotebookNoPermission = "ModelArts.6407"
NotebookInvalid = "ModelArts.6400"
UnknownErrorPrefix = "UNKNOWN:"
)

func getHttpClient() *http.Client {
if httpClient == nil {
httpClient = &http.Client{
Timeout: 30 * time.Second,
Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}},
}
}
return httpClient
}

func GetNotebook(jobID string) (*models.GetNotebook2Result, error) {
var result models.GetNotebook2Result

client := getHttpClient()
s := core.Signer{
Key: setting.ModelartsCD.AccessKey,
Secret: setting.ModelartsCD.SecretKey,
}
r, _ := http.NewRequest(http.MethodGet,
setting.ModelartsCD.EndPoint+"/v1/"+setting.ModelartsCD.ProjectID+urlNotebook2+"/"+jobID,
nil)

r.Header.Add("content-type", "application/json")
s.Sign(r)

resp, err := client.Do(r)
if err != nil {
log.Error("client.Do failed: %s", err.Error())
return &result, fmt.Errorf("client.Do failed: %s", err.Error())
}

defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Error("ioutil.ReadAll failed: %s", err.Error())
return &result, fmt.Errorf("ioutil.ReadAll failed: %s", err.Error())
}

err = json.Unmarshal(body, &result)
if err != nil {
log.Error("json.Unmarshal failed: %s", err.Error())
return &result, fmt.Errorf("son.Unmarshal failed: %s", err.Error())
}

if len(result.ErrorCode) != 0 {
log.Error("GetNotebook failed(%s): %s", result.ErrorCode, result.ErrorMsg)
return &result, fmt.Errorf("GetNotebook failed(%s): %s", result.ErrorCode, result.ErrorMsg)
}

return &result, nil
}

func ManageNotebook(jobID string, param models.NotebookAction) (*models.NotebookActionResult, error) {
var result models.NotebookActionResult

client := getHttpClient()
s := core.Signer{
Key: setting.ModelartsCD.AccessKey,
Secret: setting.ModelartsCD.SecretKey,
}
r, _ := http.NewRequest(http.MethodPost,
setting.ModelartsCD.EndPoint+"/v1/"+setting.ModelartsCD.ProjectID+urlNotebook2+"/"+jobID+"/"+param.Action+"?duration="+strconv.Itoa(autoStopDurationMs),
nil)

r.Header.Add("content-type", "application/json")
s.Sign(r)

resp, err := client.Do(r)
if err != nil {
log.Error("client.Do failed: %s", err.Error())
return &result, fmt.Errorf("client.Do failed: %s", err.Error())
}

defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Error("ioutil.ReadAll failed: %s", err.Error())
return &result, fmt.Errorf("ioutil.ReadAll failed: %s", err.Error())
}

err = json.Unmarshal(body, &result)
if err != nil {
log.Error("json.Unmarshal failed: %s", err.Error())
return &result, fmt.Errorf("son.Unmarshal failed: %s", err.Error())
}

if len(result.ErrorCode) != 0 {
log.Error("ManageNotebook2 failed(%s): %s", result.ErrorCode, result.ErrorMsg)
return &result, fmt.Errorf("ManageNotebook failed(%s): %s", result.ErrorCode, result.ErrorMsg)
}

return &result, nil
}

func DelNotebook(jobID string) (*models.NotebookDelResult, error) {
var result models.NotebookDelResult

client := getHttpClient()
s := core.Signer{
Key: setting.ModelartsCD.AccessKey,
Secret: setting.ModelartsCD.SecretKey,
}

r, _ := http.NewRequest(http.MethodDelete,
setting.ModelartsCD.EndPoint+"/v1/"+setting.ModelartsCD.ProjectID+urlNotebook2+"/"+jobID,
nil)

r.Header.Add("content-type", "application/json")
s.Sign(r)

resp, err := client.Do(r)
if err != nil {
log.Error("client.Do failed: %s", err.Error())
return &result, fmt.Errorf("client.Do failed: %s", err.Error())
}

defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Error("ioutil.ReadAll failed: %s", err.Error())
return &result, fmt.Errorf("ioutil.ReadAll failed: %s", err.Error())
}

err = json.Unmarshal(body, &result)
if err != nil {
log.Error("json.Unmarshal failed: %s", err.Error())
return &result, fmt.Errorf("son.Unmarshal failed: %s", err.Error())
}

if len(result.ErrorCode) != 0 {
log.Error("DelNotebook2 failed(%s): %s", result.ErrorCode, result.ErrorMsg)
return &result, fmt.Errorf("DelNotebook2 failed(%s): %s", result.ErrorCode, result.ErrorMsg)
}

return &result, nil
}

func createNotebook(createJobParams models.CreateNotebookWithoutPoolParams) (*models.CreateNotebookResult, error) {
var result models.CreateNotebookResult
client := getHttpClient()
s := core.Signer{
Key: setting.ModelartsCD.AccessKey,
Secret: setting.ModelartsCD.SecretKey,
}

req, _ := json.Marshal(createJobParams)
r, _ := http.NewRequest(http.MethodPost,
setting.ModelartsCD.EndPoint+"/v1/"+setting.ModelartsCD.ProjectID+urlNotebook2,
ioutil.NopCloser(bytes.NewBuffer(req)))

r.Header.Add("content-type", "application/json")
s.Sign(r)

resp, err := client.Do(r)
if err != nil {
log.Error("client.Do failed: %s", err.Error())
return &result, fmt.Errorf("client.Do failed: %s", err.Error())
}

defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Error("ioutil.ReadAll failed: %s", err.Error())
return &result, fmt.Errorf("ioutil.ReadAll failed: %s", err.Error())
}

err = json.Unmarshal(body, &result)
if err != nil {
log.Error("json.Unmarshal failed: %s", err.Error())
return &result, fmt.Errorf("json.Unmarshal failed: %s", err.Error())
}

if len(result.ErrorCode) != 0 {
log.Error("createNotebook failed(%s): %s", result.ErrorCode, result.ErrorMsg)
if result.ErrorCode == errorCodeExceedLimit {
result.ErrorMsg = "所选规格使用数量已超过最大配额限制。"
}
return &result, fmt.Errorf("createNotebook failed(%s): %s", result.ErrorCode, result.ErrorMsg)
}

return &result, nil
}

+ 42
- 0
modules/modelarts_gateway/core/escape.go View File

@@ -0,0 +1,42 @@
// based on https://github.com/golang/go/blob/master/src/net/url/url.go
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package core

func shouldEscape(c byte) bool {
if 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '_' || c == '-' || c == '~' || c == '.' {
return false
}
return true
}
func escape(s string) string {
hexCount := 0
for i := 0; i < len(s); i++ {
c := s[i]
if shouldEscape(c) {
hexCount++
}
}

if hexCount == 0 {
return s
}

t := make([]byte, len(s)+2*hexCount)
j := 0
for i := 0; i < len(s); i++ {
switch c := s[i]; {
case shouldEscape(c):
t[j] = '%'
t[j+1] = "0123456789ABCDEF"[c>>4]
t[j+2] = "0123456789ABCDEF"[c&15]
j += 3
default:
t[j] = s[i]
j++
}
}
return string(t)
}

+ 208
- 0
modules/modelarts_gateway/core/signer.go View File

@@ -0,0 +1,208 @@
// HWS API Gateway Signature
// based on https://github.com/datastream/aws/blob/master/signv4.go
// Copyright (c) 2014, Xianjie

package core

import (
"bytes"
"crypto/hmac"
"crypto/sha256"
"fmt"
"io/ioutil"
"net/http"
"sort"
"strings"
"time"
)

const (
BasicDateFormat = "20060102T150405Z"
Algorithm = "SDK-HMAC-SHA256"
HeaderXDate = "X-Sdk-Date"
HeaderHost = "host"
HeaderAuthorization = "Authorization"
HeaderContentSha256 = "X-Sdk-Content-Sha256"
)

func hmacsha256(key []byte, data string) ([]byte, error) {
h := hmac.New(sha256.New, []byte(key))
if _, err := h.Write([]byte(data)); err != nil {
return nil, err
}
return h.Sum(nil), nil
}

// Build a CanonicalRequest from a regular request string
//
// CanonicalRequest =
// HTTPRequestMethod + '\n' +
// CanonicalURI + '\n' +
// CanonicalQueryString + '\n' +
// CanonicalHeaders + '\n' +
// SignedHeaders + '\n' +
// HexEncode(Hash(RequestPayload))
func CanonicalRequest(r *http.Request, signedHeaders []string) (string, error) {
var hexencode string
var err error
if hex := r.Header.Get(HeaderContentSha256); hex != "" {
hexencode = hex
} else {
data, err := RequestPayload(r)
if err != nil {
return "", err
}
hexencode, err = HexEncodeSHA256Hash(data)
if err != nil {
return "", err
}
}
return fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n%s", r.Method, CanonicalURI(r), CanonicalQueryString(r), CanonicalHeaders(r, signedHeaders), strings.Join(signedHeaders, ";"), hexencode), err
}

// CanonicalURI returns request uri
func CanonicalURI(r *http.Request) string {
pattens := strings.Split(r.URL.Path, "/")
var uri []string
for _, v := range pattens {
uri = append(uri, escape(v))
}
urlpath := strings.Join(uri, "/")
if len(urlpath) == 0 || urlpath[len(urlpath)-1] != '/' {
urlpath = urlpath + "/"
}
return urlpath
}

// CanonicalQueryString
func CanonicalQueryString(r *http.Request) string {
var keys []string
query := r.URL.Query()
for key := range query {
keys = append(keys, key)
}
sort.Strings(keys)
var a []string
for _, key := range keys {
k := escape(key)
sort.Strings(query[key])
for _, v := range query[key] {
kv := fmt.Sprintf("%s=%s", k, escape(v))
a = append(a, kv)
}
}
queryStr := strings.Join(a, "&")
r.URL.RawQuery = queryStr
return queryStr
}

// CanonicalHeaders
func CanonicalHeaders(r *http.Request, signerHeaders []string) string {
var a []string
header := make(map[string][]string)
for k, v := range r.Header {
header[strings.ToLower(k)] = v
}
for _, key := range signerHeaders {
value := header[key]
if strings.EqualFold(key, HeaderHost) {
value = []string{r.Host}
}
sort.Strings(value)
for _, v := range value {
a = append(a, key+":"+strings.TrimSpace(v))
}
}
return fmt.Sprintf("%s\n", strings.Join(a, "\n"))
}

// SignedHeaders
func SignedHeaders(r *http.Request) []string {
var a []string
for key := range r.Header {
a = append(a, strings.ToLower(key))
}
sort.Strings(a)
return a
}

// RequestPayload
func RequestPayload(r *http.Request) ([]byte, error) {
if r.Body == nil {
return []byte(""), nil
}
b, err := ioutil.ReadAll(r.Body)
if err != nil {
return []byte(""), err
}
r.Body = ioutil.NopCloser(bytes.NewBuffer(b))
return b, err
}

// Create a "String to Sign".
func StringToSign(canonicalRequest string, t time.Time) (string, error) {
hash := sha256.New()
_, err := hash.Write([]byte(canonicalRequest))
if err != nil {
return "", err
}
return fmt.Sprintf("%s\n%s\n%x",
Algorithm, t.UTC().Format(BasicDateFormat), hash.Sum(nil)), nil
}

// Create the HWS Signature.
func SignStringToSign(stringToSign string, signingKey []byte) (string, error) {
hm, err := hmacsha256(signingKey, stringToSign)
return fmt.Sprintf("%x", hm), err
}

// HexEncodeSHA256Hash returns hexcode of sha256
func HexEncodeSHA256Hash(body []byte) (string, error) {
hash := sha256.New()
if body == nil {
body = []byte("")
}
_, err := hash.Write(body)
return fmt.Sprintf("%x", hash.Sum(nil)), err
}

// Get the finalized value for the "Authorization" header. The signature parameter is the output from SignStringToSign
func AuthHeaderValue(signature, accessKey string, signedHeaders []string) string {
return fmt.Sprintf("%s Access=%s, SignedHeaders=%s, Signature=%s", Algorithm, accessKey, strings.Join(signedHeaders, ";"), signature)
}

// Signature HWS meta
type Signer struct {
Key string
Secret string
}

// SignRequest set Authorization header
func (s *Signer) Sign(r *http.Request) error {
var t time.Time
var err error
var dt string
if dt = r.Header.Get(HeaderXDate); dt != "" {
t, err = time.Parse(BasicDateFormat, dt)
}
if err != nil || dt == "" {
t = time.Now()
r.Header.Set(HeaderXDate, t.UTC().Format(BasicDateFormat))
}
signedHeaders := SignedHeaders(r)
canonicalRequest, err := CanonicalRequest(r, signedHeaders)
if err != nil {
return err
}
stringToSign, err := StringToSign(canonicalRequest, t)
if err != nil {
return err
}
signature, err := SignStringToSign(stringToSign, []byte(s.Secret))
if err != nil {
return err
}
authValue := AuthHeaderValue(signature, s.Key, signedHeaders)
r.Header.Set(HeaderAuthorization, authValue)
return nil
}

+ 75
- 7
modules/setting/setting.go View File

@@ -75,6 +75,26 @@ type C2NetSqInfos struct {
C2NetSqInfo []*C2NetSequenceInfo `json:"sequence"`
}

type StFlavorInfos struct {
FlavorInfo []*FlavorInfo `json:"flavor_info"`
}

type FlavorInfo struct {
Id int `json:"id"`
Value string `json:"value"`
Desc string `json:"desc"`
}

type StImageInfosModelArts struct {
ImageInfo []*ImageInfoModelArts `json:"image_info"`
}

type ImageInfoModelArts struct {
Id string `json:"id"`
Value string `json:"value"`
Desc string `json:"desc"`
}

var (
// AppVer settings
AppVer string
@@ -538,18 +558,31 @@ var (
AllowedOrg string
ProfileID string
PoolInfos string
Flavor string
FlavorInfos string
DebugHost string
ImageInfos string
Capacity int
MaxTempQueryTimes int
StFlavorInfo *StFlavorInfos
StImageInfos *StImageInfosModelArts
//train-job
ResourcePools string
Engines string
EngineVersions string
FlavorInfos string
TrainJobFLAVORINFOS string
ModelArtsSpecialPools string
ModelArtsMultiNode string

// modelarts-cd config
ModelartsCD = struct {
Enabled bool
EndPoint string
ProjectID string
AccessKey string
SecretKey string
ImageInfos string
FlavorInfos string
}{}

//grampus config
Grampus = struct {
@@ -1432,9 +1465,8 @@ func NewContext() {
AllowedOrg = sec.Key("ORGANIZATION").MustString("")
ProfileID = sec.Key("PROFILE_ID").MustString("")
PoolInfos = sec.Key("POOL_INFOS").MustString("")
Flavor = sec.Key("FLAVOR").MustString("")
ImageInfos = sec.Key("IMAGE_INFOS").MustString("")
Capacity = sec.Key("IMAGE_INFOS").MustInt(100)
Capacity = sec.Key("CAPACITY").MustInt(100)
MaxTempQueryTimes = sec.Key("MAX_TEMP_QUERY_TIMES").MustInt(30)
ResourcePools = sec.Key("Resource_Pools").MustString("")
Engines = sec.Key("Engines").MustString("")
@@ -1442,6 +1474,7 @@ func NewContext() {
FlavorInfos = sec.Key("FLAVOR_INFOS").MustString("")
TrainJobFLAVORINFOS = sec.Key("TrainJob_FLAVOR_INFOS").MustString("")
ModelArtsSpecialPools = sec.Key("SPECIAL_POOL").MustString("")
ModelArtsMultiNode=sec.Key("MULTI_NODE").MustString("")

sec = Cfg.Section("elk")
ElkUrl = sec.Key("ELKURL").MustString("")
@@ -1489,8 +1522,8 @@ func NewContext() {
Course.OrgName = sec.Key("org_name").MustString("")
Course.TeamName = sec.Key("team_name").MustString("")

GetGrampusConfig()
getGrampusConfig()
getModelartsCDConfig()
getModelConvertConfig()
}

@@ -1513,7 +1546,22 @@ func getModelConvertConfig() {
ModelConvert.NPU_TENSORFLOW_IMAGE_ID = sec.Key("NPU_TENSORFLOW_IMAGE_ID").MustInt(35)
}

func GetGrampusConfig() {
func getModelartsCDConfig() {
sec := Cfg.Section("modelarts-cd")

ModelartsCD.Enabled = sec.Key("ENABLED").MustBool(false)
ModelartsCD.EndPoint = sec.Key("ENDPOINT").MustString("https://modelarts.cn-southwest-228.cdzs.cn")
ModelartsCD.ProjectID = sec.Key("PROJECT_ID").MustString("")
ModelartsCD.AccessKey = sec.Key("ACCESS_KEY").MustString("")
ModelartsCD.SecretKey = sec.Key("SECRET_KEY").MustString("")
ModelartsCD.ImageInfos = sec.Key("IMAGE_INFOS").MustString("")
ModelartsCD.FlavorInfos = sec.Key("FLAVOR_INFOS").MustString("")

getNotebookImageInfos()
getNotebookFlavorInfos()
}

func getGrampusConfig() {
sec := Cfg.Section("grampus")

Grampus.Env = sec.Key("ENV").MustString("TEST")
@@ -1647,6 +1695,26 @@ func ensureLFSDirectory() {
}
}

func getNotebookImageInfos() {
if StImageInfos == nil {
if ModelartsCD.Enabled {
json.Unmarshal([]byte(ModelartsCD.ImageInfos), &StImageInfos)
} else {
json.Unmarshal([]byte(ImageInfos), &StImageInfos)
}
}
}

func getNotebookFlavorInfos() {
if StFlavorInfo == nil {
if ModelartsCD.Enabled {
json.Unmarshal([]byte(ModelartsCD.FlavorInfos), &StFlavorInfo)
} else {
json.Unmarshal([]byte(FlavorInfos), &StFlavorInfo)
}
}
}

// NewServices initializes the services
func NewServices() {
InitDBConfig()


+ 13
- 7
options/locale/locale_en-US.ini View File

@@ -960,6 +960,7 @@ unfavorite=Unlike
favorite=Like
disassociate=Disassociate
benchmark_dataset_tip=Note: first use the dataset function to upload the model, and then select the model from the dataset list.
file_deleted=The file has been deleted

[repo]
owner = Owner
@@ -1079,6 +1080,7 @@ balance.total_view = Total Balance
balance.available = Available Balance:
cloudbrain1 = cloudbrain1
cloudbrain2 = cloudbrain2
cdCenter = cd_ai_center
cloudbrain_selection = select cloudbrain
cloudbrain_platform_selection = Select the cloudbrain platform you want to use:
confirm_choice = Confirm
@@ -1141,7 +1143,7 @@ modelarts.train_job.compute_node=Compute Node
modelarts.create_model = Create Model
modelarts.model_label=Model Label
modelarts.infer_dataset = Inference Dataset
modelarts.train_job.label_place=Input labels, multiple labels are separated by spaces

modelarts.train_job.basic_info=Basic Info
modelarts.train_job.job_status=Job Status
@@ -1213,6 +1215,7 @@ modelarts.infer_job.select_model = Select Model
modelarts.infer_job.boot_file_helper=The startup file is the entry file for your program execution and must end in.py.Such as inference.py, main.py, example/inference.py, case/main.py.
modelarts.infer_job.tooltip = The model has been deleted and cannot be viewed.
modelarts.download_log=Download log file
modelarts.no_node_right = The value of 'Amount of Compute Node' is wrong, you have no right to use the current value of 'Amount of Compute Node'.


debug_task_not_created = Debug task has not been created
@@ -1222,7 +1225,10 @@ model_Evaluation_not_created = Model evaluation has not been created
repo_not_initialized = Code version: You have not initialized the code repository, please <a href="%s"> initialized </a> first ;
debug_task_running_limit =Running time: no more than 4 hours, it will automatically stop if it exceeds 4 hours;
dataset_desc = Dataset: Cloud Brain 1 provides CPU/GPU,Cloud Brain 2 provides Ascend NPU.And dataset also needs to be uploaded to the corresponding environment;
platform_instructions = Instructions for use: You can refer to the <a href="https://git.openi.org.cn/zeizei/OpenI_Learning"> OpenI_Learning </a> course of Openi AI collaboration platform.
platform_instructions = Instructions for use: You can refer to the <a href="https://git.openi.org.cn/zeizei/OpenI_Learning"> OpenI_Learning </a> course of Qizhi AI collaboration platform.
platform_instructions1 = Instructions for use: You can refer to the
platform_instructions2 = OpenI_Learning
platform_instructions3 = course of Openi AI collaboration platform.
model_not_exist = Model file: You do not have a model file yet, please generate and <a href="%s/modelmanage/show_model">export the model</a> through the <a href="%s/modelarts/train-job">training task</a> first ;
benchmark_leaderboards = Benchmark leaderboards

@@ -1245,11 +1251,11 @@ model.convert=Model Transformation
model.list=Model List
model.manage.create_new_convert_task=Create Model Transformation Task

model.manage.notcreatemodel=No model has been created.
model.manage.notcreatemodel=No model has been created
model.manage.init1=Code version: You have not initialized the code repository, please
model.manage.init2=initialized first ;
model.manage.createtrainjob_tip=Training task: you haven't created a training task, please create it first
model.manage.createtrainjob=Training task
model.manage.createtrainjob=Training task.
model.manage.delete=Delete Model
model.manage.delete_confirm=Are you sure to delete this model? Once this model is deleted, it cannot be restored.
model.manage.select.trainjob=Select train task
@@ -1261,9 +1267,9 @@ model.manage.modellabel=Model label
model.manage.modeldesc=Model description
model.manage.baseinfo=Base Information
modelconvert.notcreate=No model conversion task has been created.
modelconvert.importfirst1=Please import first
modelconvert.importfirst2=download model
modelconvert.importfirst3=, then converts it.
modelconvert.importfirst1=Please import the
modelconvert.importfirst2=model
modelconvert.importfirst3=first, then converts it.
modelconvert.download=Download
modelconvert.taskname=Task name
modelconvert.modelname=Model name


+ 9
- 2
options/locale/locale_zh-CN.ini View File

@@ -966,6 +966,7 @@ unfavorite=取消收藏
favorite=收藏
disassociate=取消关联
benchmark_dataset_tip=说明:先使用数据集功能上传模型,然后从数据集列表选模型。
file_deleted=文件已经被删除

[repo]
owner=拥有者
@@ -1080,6 +1081,7 @@ balance.total_view=余额总览
balance.available=可用余额:
cloudbrain1=云脑1
cloudbrain2=云脑2
cdCenter=成都智算中心
intelligent_net=智算网络
cloudbrain_selection=云脑选择
cloudbrain_platform_selection=选择您准备使用的云脑平台:
@@ -1226,6 +1228,7 @@ modelarts.infer_job.select_model = 选择模型
modelarts.infer_job.boot_file_helper=启动文件是您程序执行的入口文件,必须是以.py结尾的文件。比如inference.py、main.py、example/inference.py、case/main.py。
modelarts.infer_job.tooltip = 该模型已删除,无法查看。
modelarts.download_log=下载日志文件
modelarts.no_node_right = 计算节点数的值配置错误,您没有权限使用当前配置的计算节点数。


debug_task_not_created = 未创建过调试任务
@@ -1236,6 +1239,10 @@ repo_not_initialized = 代码版本:您还没有初始化代码仓库,请先
debug_task_running_limit = 运行时长:最长不超过4个小时,超过4个小时将自动停止;
dataset_desc = 数据集:云脑1提供 CPU / GPU 资源,云脑2提供 Ascend NPU 资源,调试使用的数据集也需要上传到对应的环境;
platform_instructions = 使用说明:可以参考启智AI协作平台<a href="https://git.openi.org.cn/zeizei/OpenI_Learning">小白训练营课程</a>。
platform_instructions1 = 使用说明:可以参考启智AI协作平台
platform_instructions2 = 小白训练营课程
platform_instructions3 = 。

model_not_exist = 模型文件:您还没有模型文件,请先通过<a href="%s/modelarts/train-job">训练任务</a>产生并 <a href="%s/modelmanage/show_model">导出模型</a> ;
benchmark_leaderboards = 基准测试排行榜

@@ -1262,7 +1269,7 @@ model.manage.notcreatemodel=未创建过模型
model.manage.init1=代码版本:您还没有初始化代码仓库,请先
model.manage.init2=创建代码版本;
model.manage.createtrainjob_tip=训练任务:您还没创建过训练任务,请先创建
model.manage.createtrainjob=训练任务
model.manage.createtrainjob=训练任务
model.manage.delete=删除模型
model.manage.delete_confirm=你确认删除该模型么?此模型一旦删除不可恢复。
model.manage.select.trainjob=选择训练任务
@@ -1275,7 +1282,7 @@ model.manage.modeldesc=模型描述
model.manage.baseinfo=基本信息
modelconvert.notcreate=未创建过模型转换任务
modelconvert.importfirst1=请您先导入
modelconvert.importfirst2=模型下载
modelconvert.importfirst2=模型
modelconvert.importfirst3=,然后再对其进行转换。
modelconvert.download=下载
modelconvert.taskname=任务名称


+ 2
- 2
routers/admin/cloudbrains.go View File

@@ -92,13 +92,13 @@ func CloudBrains(ctx *context.Context) {
return
}

models.LoadSpecs4CloudbrainInfo(ciTasks)

for i, task := range ciTasks {
ciTasks[i].CanDebug = true
ciTasks[i].CanDel = true
ciTasks[i].Cloudbrain.ComputeResource = task.ComputeResource
ciTasks[i].Cloudbrain.AiCenter = repo.GetCloudbrainAiCenter(task.Cloudbrain, ctx)
_, cardType, _ := repo.GetCloudbrainCardNumAndType(task.Cloudbrain)
ciTasks[i].Cloudbrain.CardType = cardType
ciTasks[i].Cloudbrain.Cluster = repo.GetCloudbrainCluster(task.Cloudbrain, ctx)
}



+ 139
- 30
routers/api/v1/repo/cloudbrain.go View File

@@ -405,52 +405,159 @@ func CloudbrainDownloadLogFile(ctx *context.Context) {

func CloudbrainGetLog(ctx *context.Context) {
ID := ctx.Params(":id")
startLine := ctx.QueryInt("base_line")
lines := ctx.QueryInt("lines")
endLine := startLine + lines
order := ctx.Query("order")
if order == "asc" {
endLine = startLine
startLine = endLine - lines
if startLine < 0 {
startLine = 0
}
}
job, err := models.GetCloudbrainByID(ID)
if err != nil {
log.Error("GetCloudbrainByJobName failed: %v", err, ctx.Data["MsgID"])
ctx.ServerError(err.Error(), err)
return
}
result := getLogFromModelDir(job.JobName, startLine, endLine)
if result == nil {
log.Error("GetJobLog failed: %v", err, ctx.Data["MsgID"])
ctx.ServerError(err.Error(), err)
return
lines := ctx.QueryInt("lines")
baseLine := ctx.Query("base_line")
order := ctx.Query("order")
var result map[string]interface{}
resultPath := "/model"
if job.JobType == string(models.JobTypeInference) {
resultPath = "/result"
}
if baseLine == "" && order == "desc" {
result = getLastLogFromModelDir(job.JobName, lines, resultPath)
} else {
startLine := ctx.QueryInt("base_line")
endLine := startLine + lines
if order == "asc" {
if baseLine == "" {
startLine = 0
endLine = lines
} else {
endLine = startLine
startLine = endLine - lines
if startLine < 0 {
startLine = 0
}
}
}
result = getLogFromModelDir(job.JobName, startLine, endLine, resultPath)
if result == nil {
log.Error("GetJobLog failed: %v", err, ctx.Data["MsgID"])
ctx.ServerError(err.Error(), err)
return
}
}

re := map[string]interface{}{
"JobID": ID,
"LogFileName": result["FileName"],
"StartLine": startLine,
"EndLine": result["endLine"],
"StartLine": result["StartLine"],
"EndLine": result["EndLine"],
"Content": result["Content"],
"Lines": result["lines"],
"Lines": result["Lines"],
"CanLogDownload": result["FileName"] != "",
}
//result := CloudbrainGetLogByJobId(job.JobID, job.JobName)

ctx.JSON(http.StatusOK, re)
}

func getLogFromModelDir(jobName string, startLine int, endLine int) map[string]interface{} {
prefix := "/" + setting.CBCodePathPrefix + jobName + "/model"
func getAllLineFromFile(path string) int {
count := 0
reader, err := os.Open(path)
defer reader.Close()
if err == nil {
r := bufio.NewReader(reader)
for {
_, error := r.ReadString('\n')
if error == io.EOF {
log.Info("read file completed.")
break
}
if error != nil {
log.Info("read file error." + error.Error())
break
}
count = count + 1
}
} else {
log.Info("error:" + err.Error())
}
return count
}

func getLastLogFromModelDir(jobName string, lines int, resultPath string) map[string]interface{} {
prefix := "/" + setting.CBCodePathPrefix + jobName + resultPath
files, err := storage.GetOneLevelAllObjectUnderDirMinio(setting.Attachment.Minio.Bucket, prefix, "")
if err != nil {
log.Error("query cloudbrain model failed: %v", err)
return nil
}

re := ""
fileName := ""
count := 0
allLines := 0
startLine := 0
for _, file := range files {
if strings.HasSuffix(file.FileName, "log.txt") {
fileName = file.FileName
path := storage.GetMinioPath(jobName+resultPath+"/", file.FileName)
allLines = getAllLineFromFile(path)
startLine = allLines - lines
if startLine < 0 {
startLine = 0
}
count = allLines - startLine
log.Info("path=" + path)
reader, err := os.Open(path)
defer reader.Close()
if err == nil {
r := bufio.NewReader(reader)
for i := 0; i < allLines; i++ {
line, error := r.ReadString('\n')
if error == io.EOF {
log.Info("read file completed.")
break
}
if error != nil {
log.Info("read file error." + error.Error())
break
}
if error == nil {
if i >= startLine {
re = re + line
}
}
}
} else {
log.Info("error:" + err.Error())
}
break
}
}

return map[string]interface{}{
"JobName": jobName,
"Content": re,
"FileName": fileName,
"Lines": count,
"EndLine": allLines,
"StartLine": startLine,
}
}

func getLogFromModelDir(jobName string, startLine int, endLine int, resultPath string) map[string]interface{} {
prefix := "/" + setting.CBCodePathPrefix + jobName + resultPath
files, err := storage.GetOneLevelAllObjectUnderDirMinio(setting.Attachment.Minio.Bucket, prefix, "")
if err != nil {
log.Error("query cloudbrain model failed: %v", err)
return nil
}
if startLine == endLine {
return map[string]interface{}{
"JobName": jobName,
"Content": "",
"FileName": "",
"Lines": 0,
"EndLine": startLine,
"StartLine": startLine,
}
}
re := ""
fileName := ""
count := 0
@@ -458,7 +565,7 @@ func getLogFromModelDir(jobName string, startLine int, endLine int) map[string]i
for _, file := range files {
if strings.HasSuffix(file.FileName, "log.txt") {
fileName = file.FileName
path := storage.GetMinioPath(jobName+"/model/", file.FileName)
path := storage.GetMinioPath(jobName+resultPath+"/", file.FileName)
log.Info("path=" + path)
reader, err := os.Open(path)
defer reader.Close()
@@ -467,7 +574,6 @@ func getLogFromModelDir(jobName string, startLine int, endLine int) map[string]i
for i := 0; i < endLine; i++ {
line, error := r.ReadString('\n')
log.Info("line=" + line)
fileEndLine = i
if error == io.EOF {
log.Info("read file completed.")
break
@@ -478,11 +584,13 @@ func getLogFromModelDir(jobName string, startLine int, endLine int) map[string]i
}
if error == nil {
if i >= startLine {
fileEndLine = i
re = re + line
count++
}
}
}
fileEndLine = fileEndLine + 1
} else {
log.Info("error:" + err.Error())
}
@@ -491,11 +599,12 @@ func getLogFromModelDir(jobName string, startLine int, endLine int) map[string]i
}

return map[string]interface{}{
"JobName": jobName,
"Content": re,
"FileName": fileName,
"lines": count,
"endLine": fileEndLine,
"JobName": jobName,
"Content": re,
"FileName": fileName,
"Lines": count,
"EndLine": fileEndLine,
"StartLine": startLine,
}
}



+ 12
- 7
routers/repo/cloudbrain.go View File

@@ -787,7 +787,7 @@ func cloudBrainShow(ctx *context.Context, tpName base.TplName, jobType models.Jo
}

}
ctx.Data["datasetDownload"] = GetCloudBrainDataSetInfo(task.Uuid, false)
ctx.Data["datasetDownload"] = GetCloudBrainDataSetInfo(task.Uuid, task.DatasetName, false)
ctx.Data["task"] = task
labelName := strings.Fields(task.LabelName)
ctx.Data["LabelName"] = labelName
@@ -2369,7 +2369,8 @@ func BenchMarkAlgorithmCreate(ctx *context.Context, form auth.CreateCloudBrainFo
ctx.RenderWithErr(ctx.Tr("cloudbrain.error.dataset_select"), tplCloudBrainBenchmarkNew, &form)
return
}

log.Info("Command=" + command)
log.Info("ModelPath=" + storage.GetMinioPath(jobName, cloudbrain.ModelMountPath+"/"))
req := cloudbrain.GenerateCloudBrainTaskReq{
Ctx: ctx,
DisplayJobName: displayJobName,
@@ -2512,6 +2513,8 @@ func ModelBenchmarkCreate(ctx *context.Context, form auth.CreateCloudBrainForm)
ctx.RenderWithErr(ctx.Tr("points.insufficient_points_balance"), tpl, &form)
return
}
log.Info("Command=" + command)
log.Info("ModelPath=" + storage.GetMinioPath(jobName, cloudbrain.ModelMountPath+"/"))
req := cloudbrain.GenerateCloudBrainTaskReq{
Ctx: ctx,
DisplayJobName: displayJobName,
@@ -2639,7 +2642,7 @@ func getInferenceJobCommand(form auth.CreateCloudBrainInferencForm) (string, err

param += " --modelname" + "=" + form.CkptName

command += "python /code/" + bootFile + param + " > " + cloudbrain.ResultPath + "/" + form.DisplayJobName + "-" + cloudbrain.LogFile
command += "python /code/" + bootFile + param + " | tee " + cloudbrain.ResultPath + "/" + form.DisplayJobName + "-" + cloudbrain.LogFile

return command, nil
}
@@ -2668,7 +2671,7 @@ func getTrainJobCommand(form auth.CreateCloudBrainForm) (string, error) {
}
}

command += "python /code/" + bootFile + param + " | tee " + cloudbrain.ModelMountPath + "/" + form.DisplayJobName + "-" + cloudbrain.LogFile
command += "python /code/" + bootFile + param + " > " + cloudbrain.ModelMountPath + "/" + form.DisplayJobName + "-" + cloudbrain.LogFile

return command, nil
}
@@ -2713,6 +2716,8 @@ func GetCloudbrainAiCenter(task models.Cloudbrain, ctx *context.Context) string
return ctx.Tr("repo.cloudbrain1")
} else if task.Type == models.TypeCloudBrainTwo {
return ctx.Tr("repo.cloudbrain2")
} else if task.Type == models.TypeCDCenter {
return ctx.Tr("repo.cdCenter")
} else if task.Type == models.TypeC2Net {
return getCutStringAiCenterByAiCenter(task.AiCenter)
}
@@ -2727,7 +2732,7 @@ func getCutStringAiCenterByAiCenter(aiCenter string) string {

}
func GetCloudbrainCluster(task models.Cloudbrain, ctx *context.Context) string {
if task.Type == models.TypeCloudBrainOne || task.Type == models.TypeCloudBrainTwo {
if task.Type == models.TypeCloudBrainOne || task.Type == models.TypeCloudBrainTwo || task.Type == models.TypeCDCenter {
return ctx.Tr("cloudbrain.resource_cluster_openi")
} else if task.Type == models.TypeC2Net {
return ctx.Tr("cloudbrain.resource_cluster_c2net")
@@ -2814,10 +2819,10 @@ func GetCloudbrainFlavorName(task models.Cloudbrain) (string, error) {
return CloudbrainOneFlavorName, nil
}
}
} else if (task.Type == models.TypeCloudBrainTwo || task.Type == models.TypeC2Net) && task.FlavorName != "" {
} else if (task.Type == models.TypeCloudBrainTwo || task.Type == models.TypeC2Net || task.Type == models.TypeCDCenter) && task.FlavorName != "" {
replaceFlavorName := strings.ReplaceAll(task.FlavorName, ":", ":")
return replaceFlavorName, nil
} else if task.Type == models.TypeCloudBrainTwo && task.FlavorName == "" && task.FlavorCode != "" {
} else if (task.Type == models.TypeCloudBrainTwo || task.Type == models.TypeCDCenter) && task.FlavorName == "" && task.FlavorCode != "" {
cloudbrainTwoFlavorName := getFlavorNameByFlavorCode(task.FlavorCode)
return cloudbrainTwoFlavorName, nil
} else if task.Type == models.TypeCloudBrainTwo && task.JobType == string(models.JobTypeDebug) && task.FlavorName == "" && task.FlavorCode == "" {


+ 2
- 7
routers/repo/dataset.go View File

@@ -45,15 +45,10 @@ func newFilterPrivateAttachments(ctx *context.Context, list []*models.Attachment
repo.GetOwner()
}
permission := false
if repo.Owner.IsOrganization() && ctx.User != nil {
if repo.Owner.IsUserPartOfOrg(ctx.User.ID) {
log.Info("user is member of org.")
permission = true
}
}
if !permission && ctx.User != nil {
isCollaborator, _ := repo.IsCollaborator(ctx.User.ID)
if isCollaborator {
isInRepoTeam,_:=repo.IsInRepoTeam(ctx.User.ID)
if isCollaborator ||isInRepoTeam {
log.Info("Collaborator user may visit the attach.")
permission = true
}


+ 1
- 1
routers/repo/grampus.go View File

@@ -754,7 +754,7 @@ func GrampusTrainJobShow(ctx *context.Context) {
taskList = append(taskList, task)
prepareSpec4Show(ctx, task)
ctx.Data["version_list_task"] = taskList
ctx.Data["datasetDownload"] = GetCloudBrainDataSetInfo(task.Uuid, false)
ctx.Data["datasetDownload"] = GetCloudBrainDataSetInfo(task.Uuid, task.DatasetName, false)
ctx.Data["canDownload"] = cloudbrain.CanModifyJob(ctx, task)
ctx.Data["displayJobName"] = task.DisplayJobName



+ 194
- 95
routers/repo/modelarts.go View File

@@ -2,10 +2,12 @@ package repo

import (
"archive/zip"
"code.gitea.io/gitea/modules/modelarts_cd"
"code.gitea.io/gitea/services/cloudbrain/resource"
"code.gitea.io/gitea/services/reward/point/account"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
@@ -61,18 +63,11 @@ func DebugJobIndex(ctx *context.Context) {
if page <= 0 {
page = 1
}
typeCloudBrain := models.TypeCloudBrainAll
jobTypeNot := false
if listType == models.GPUResource {
typeCloudBrain = models.TypeCloudBrainOne
} else if listType == models.NPUResource {
typeCloudBrain = models.TypeCloudBrainTwo
} else if listType == models.AllResource {
typeCloudBrain = models.TypeCloudBrainAll
} else {
log.Error("listType(%s) error", listType)
ctx.ServerError("listType error", errors.New("listType error"))
return
var computeResource string
if listType != models.AllResource {
computeResource = listType
}

var jobTypes []string
@@ -82,10 +77,11 @@ func DebugJobIndex(ctx *context.Context) {
Page: page,
PageSize: setting.UI.IssuePagingNum,
},
RepoID: repo.ID,
Type: typeCloudBrain,
JobTypeNot: jobTypeNot,
JobTypes: jobTypes,
RepoID: repo.ID,
ComputeResource: computeResource,
Type: models.TypeCloudBrainAll,
JobTypeNot: jobTypeNot,
JobTypes: jobTypes,
})
if err != nil {
ctx.ServerError("Get debugjob faild:", err)
@@ -135,11 +131,7 @@ func notebookNewDataPrepare(ctx *context.Context) error {
return err
}
ctx.Data["attachments"] = attachs

if modelarts.ImageInfos == nil {
json.Unmarshal([]byte(setting.ImageInfos), &modelarts.ImageInfos)
}
ctx.Data["images"] = modelarts.ImageInfos.ImageInfo
ctx.Data["images"] = setting.StImageInfos.ImageInfo

prepareCloudbrainTwoDebugSpecs(ctx)

@@ -152,11 +144,15 @@ func notebookNewDataPrepare(ctx *context.Context) error {
}

func prepareCloudbrainTwoDebugSpecs(ctx *context.Context) {
aiCenterCode := models.AICenterOfCloudBrainTwo
if setting.ModelartsCD.Enabled {
aiCenterCode = models.AICenterOfChengdu
}
noteBookSpecs, _ := resource.FindAvailableSpecs(ctx.User.ID, models.FindSpecsOptions{
JobType: models.JobTypeDebug,
ComputeResource: models.NPU,
Cluster: models.OpenICluster,
AiCenterCode: models.AICenterOfCloudBrainTwo,
AiCenterCode: aiCenterCode,
})
ctx.Data["Specs"] = noteBookSpecs
}
@@ -245,12 +241,15 @@ func Notebook2Create(ctx *context.Context, form auth.CreateModelArtsNotebookForm
return
}
}

var aiCenterCode = models.AICenterOfCloudBrainTwo
if setting.ModelartsCD.Enabled {
aiCenterCode = models.AICenterOfChengdu
}
spec, err := resource.GetAndCheckSpec(ctx.User.ID, form.SpecId, models.FindSpecsOptions{
JobType: models.JobTypeDebug,
ComputeResource: models.NPU,
Cluster: models.OpenICluster,
AiCenterCode: models.AICenterOfCloudBrainTwo})
AiCenterCode: aiCenterCode})
if err != nil || spec == nil {
notebookNewDataPrepare(ctx)
ctx.RenderWithErr("Resource specification not available", tplModelArtsNotebookNew, &form)
@@ -263,7 +262,12 @@ func Notebook2Create(ctx *context.Context, form auth.CreateModelArtsNotebookForm
return
}

err = modelarts.GenerateNotebook2(ctx, displayJobName, jobName, uuid, description, imageId, spec)
if setting.ModelartsCD.Enabled {
err = modelarts_cd.GenerateNotebook(ctx, displayJobName, jobName, uuid, description, imageId, spec)
} else {
err = modelarts.GenerateNotebook2(ctx, displayJobName, jobName, uuid, description, imageId, spec)
}

if err != nil {
log.Error("GenerateNotebook2 failed, %v", err, ctx.Data["MsgID"])
notebookNewDataPrepare(ctx)
@@ -301,7 +305,7 @@ func NotebookShow(ctx *context.Context) {
datasetDownload := make([]models.DatasetDownload, 0)
if ctx.IsSigned {
if task.Uuid != "" && task.UserID == ctx.User.ID {
datasetDownload = GetCloudBrainDataSetInfo(task.Uuid, true)
datasetDownload = GetCloudBrainDataSetInfo(task.Uuid, task.DatasetName, true)
}
}
user, err := models.GetUserByID(task.UserID)
@@ -330,36 +334,52 @@ func NotebookShow(ctx *context.Context) {
ctx.HTML(200, tplModelArtsNotebookShow)
}

func GetCloudBrainDataSetInfo(uuid string, isNeedDown bool) []models.DatasetDownload {
func GetCloudBrainDataSetInfo(uuid string, datasetname string, isNeedDown bool) []models.DatasetDownload {
datasetDownload := make([]models.DatasetDownload, 0)

if len(uuid) == 0 {
return datasetDownload
}
uuidList := strings.Split(uuid, ";")
for _, uuidStr := range uuidList {
datasetnameList := strings.Split(datasetname, ";")
for i, uuidStr := range uuidList {
name := ""
link := ""
url := ""
isDelete := false
attachment, err := models.GetAttachmentByUUID(uuidStr)
if err != nil {
log.Error("GetAttachmentByUUID failed:%v", err.Error())
return datasetDownload
}
dataset, err := models.GetDatasetByID(attachment.DatasetID)
if err != nil {
log.Error("GetDatasetByID failed:%v", err.Error())
return datasetDownload
}
repo, err := models.GetRepositoryByID(dataset.RepoID)
if err != nil {
log.Error("GetRepositoryByID failed:%v", err.Error())
return datasetDownload
}
url := ""
if isNeedDown {
url = attachment.S3DownloadURL()
if len(datasetnameList) <= i || len(datasetname) == 0 {
continue
}
name = datasetnameList[i]
isDelete = true
} else {
name = attachment.Name
dataset, err := models.GetDatasetByID(attachment.DatasetID)
if err != nil {
log.Error("GetDatasetByID failed:%v", err.Error())
} else {
repo, err := models.GetRepositoryByID(dataset.RepoID)
if err != nil {
log.Error("GetRepositoryByID failed:%v", err.Error())
} else {
link = repo.Link() + "/datasets"
}
}
if isNeedDown {
url = attachment.S3DownloadURL()
}
}

datasetDownload = append(datasetDownload, models.DatasetDownload{
DatasetName: attachment.Name,
DatasetName: name,
DatasetDownloadLink: url,
RepositoryLink: repo.Link() + "/datasets",
RepositoryLink: link,
IsDelete: isDelete,
})
}
log.Info("dataset length=" + fmt.Sprint(len(datasetDownload)))
return datasetDownload
}

@@ -377,36 +397,16 @@ func setShowSpecBySpecialPoolConfig(ctx *context.Context, findSpec bool, task *m
}
}

func NotebookDebug(ctx *context.Context) {
var jobID = ctx.Params(":jobid")

result, err := modelarts.GetJob(jobID)
if err != nil {
ctx.RenderWithErr(err.Error(), tplModelArtsNotebookIndex, nil)
return
}

res, err := modelarts.GetJobToken(jobID)
if err != nil {
ctx.RenderWithErr(err.Error(), tplModelArtsNotebookIndex, nil)
return
}

urls := strings.Split(result.Spec.Annotations.Url, "/")
urlPrefix := result.Spec.Annotations.TargetDomain
for i, url := range urls {
if i > 2 {
urlPrefix += "/" + url
}
}

debugUrl := urlPrefix + "?token=" + res.Token
ctx.Redirect(debugUrl)
}

func NotebookDebug2(ctx *context.Context) {
var err error
var result *models.GetNotebook2Result
task := ctx.Cloudbrain
result, err := modelarts.GetNotebook2(task.JobID)
if task.Type == models.TypeCloudBrainTwo {
result, err = modelarts.GetNotebook2(task.JobID)
} else if task.Type == models.TypeCDCenter {
result, err = modelarts_cd.GetNotebook(task.JobID)
}

if err != nil {
ctx.RenderWithErr(err.Error(), tplModelArtsNotebookIndex, nil)
return
@@ -454,11 +454,16 @@ func NotebookRestart(ctx *context.Context) {
errorMsg = "Resource specification not available"
break
}

aiCenterCode := models.AICenterOfCloudBrainTwo
if task.Type == models.TypeCDCenter {
aiCenterCode = models.AICenterOfChengdu
}
spec, err = resource.GetAndCheckSpec(ctx.User.ID, oldSpec.ID, models.FindSpecsOptions{
JobType: models.JobType(task.JobType),
ComputeResource: models.NPU,
Cluster: models.OpenICluster,
AiCenterCode: models.AICenterOfCloudBrainTwo})
AiCenterCode: aiCenterCode})
if err != nil || spec == nil {
log.Error("NotebookManage GetAndCheckSpec error.task.id = %d", task.ID)
errorMsg = "Resource specification not support any more"
@@ -474,7 +479,13 @@ func NotebookRestart(ctx *context.Context) {
Action: models.ActionStart,
}

res, err := modelarts.ManageNotebook2(task.JobID, param)
var res *models.NotebookActionResult
if task.Type == models.TypeCloudBrainTwo {
res, err = modelarts.ManageNotebook2(task.JobID, param)
} else if task.Type == models.TypeCDCenter {
res, err = modelarts_cd.ManageNotebook(task.JobID, param)
}

if err != nil {
log.Error("ManageNotebook2(%s) failed:%v", task.DisplayJobName, err.Error(), ctx.Data["MsgID"])
/* 暂不处理再次调试502的场景,详情见方案
@@ -559,7 +570,14 @@ func NotebookStop(ctx *context.Context) {
Action: models.ActionStop,
}

res, err := modelarts.ManageNotebook2(task.JobID, param)
var err error
var res *models.NotebookActionResult
if task.Type == models.TypeCloudBrainTwo {
res, err = modelarts.ManageNotebook2(task.JobID, param)
} else if task.Type == models.TypeCDCenter {
res, err = modelarts_cd.ManageNotebook(task.JobID, param)
}

if err != nil {
log.Error("ManageNotebook2(%s) failed:%v", task.JobName, err.Error(), ctx.Data["MsgID"])
resultCode = "-1"
@@ -609,7 +627,13 @@ func NotebookDel(ctx *context.Context) {
return
}

_, err := modelarts.DelNotebook2(task.JobID)
var err error
if task.Type == models.TypeCloudBrainTwo {
_, err = modelarts.DelNotebook2(task.JobID)
} else if task.Type == models.TypeCDCenter {
_, err = modelarts_cd.DelNotebook(task.JobID)
}

if err != nil {
log.Error("DelNotebook2(%s) failed:%v", task.JobName, err.Error())
if strings.Contains(err.Error(), modelarts.NotebookNotFound) || strings.Contains(err.Error(), modelarts.NotebookNoPermission) || strings.Contains(err.Error(), modelarts.NotebookInvalid) {
@@ -760,6 +784,8 @@ func trainJobNewDataPrepare(ctx *context.Context) error {
waitCount := cloudbrain.GetWaitingCloudbrainCount(models.TypeCloudBrainTwo, "")
ctx.Data["WaitCount"] = waitCount

setMultiNodeIfConfigureMatch(ctx)

return nil
}

@@ -773,6 +799,18 @@ func prepareCloudbrainTwoTrainSpecs(ctx *context.Context) {
ctx.Data["Specs"] = noteBookSpecs
}

func setMultiNodeIfConfigureMatch(ctx *context.Context) {
modelarts.InitMultiNode()
if modelarts.MultiNodeConfig != nil {
for _, info := range modelarts.MultiNodeConfig.Info {
if isInOrg, _ := models.IsOrganizationMemberByOrgName(info.Org, ctx.User.ID); isInOrg {
ctx.Data["WorkNode"] = info.Node
break
}
}
}
}

func setSpecBySpecialPoolConfig(ctx *context.Context, jobType string) {
modelarts.InitSpecialPool()

@@ -881,6 +919,7 @@ func trainJobErrorNewDataPrepare(ctx *context.Context, form auth.CreateModelArts
ctx.Data["datasetType"] = models.TypeCloudBrainTwo
waitCount := cloudbrain.GetWaitingCloudbrainCount(models.TypeCloudBrainTwo, "")
ctx.Data["WaitCount"] = waitCount
setMultiNodeIfConfigureMatch(ctx)

return nil
}
@@ -944,6 +983,11 @@ func trainJobNewVersionDataPrepare(ctx *context.Context) error {
ctx.Data["engine_versions"] = versionInfos.Version

prepareCloudbrainTwoTrainSpecs(ctx)
spec, _ := resource.GetCloudbrainSpec(task.ID)
if spec != nil {
log.Info("spec_id = %d", spec.ID)
ctx.Data["spec_id"] = spec.ID
}

var Parameters modelarts.Parameters
if err = json.Unmarshal([]byte(task.Parameters), &Parameters); err != nil {
@@ -959,14 +1003,17 @@ func trainJobNewVersionDataPrepare(ctx *context.Context) error {
}
_, _, datasetNames, _, err := getDatasUrlListByUUIDS(task.Uuid)
if err != nil {
ctx.ServerError("GetAllUserAttachments failed:", err)
return err
log.Info("query dataset error," + err.Error())
//ctx.ServerError("GetAllUserAttachments failed:", err)
//return err
} else {
ctx.Data["dataset_name"] = datasetNames
}
ctx.Data["branches"] = branches
ctx.Data["branch_name"] = task.BranchName
ctx.Data["description"] = task.Description
ctx.Data["boot_file"] = task.BootFile
ctx.Data["dataset_name"] = datasetNames
ctx.Data["work_server_number"] = task.WorkServerNumber
ctx.Data["flavor_name"] = task.FlavorName
ctx.Data["engine_name"] = task.EngineName
@@ -1099,6 +1146,13 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm)
VersionCount := modelarts.VersionCountOne
EngineName := form.EngineName

errStr := checkMultiNode(ctx.User.ID, form.WorkServerNumber)
if errStr != "" {
trainJobErrorNewDataPrepare(ctx, form)
ctx.RenderWithErr(ctx.Tr(errStr), tplModelArtsTrainJobNew, &form)
return
}

count, err := models.GetCloudbrainTrainJobCountByUserID(ctx.User.ID)
if err != nil {
log.Error("GetCloudbrainTrainJobCountByUserID failed:%v", err, ctx.Data["MsgID"])
@@ -1344,6 +1398,48 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm)
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/train-job")
}

func checkMultiNode(userId int64, serverNum int) string {
if serverNum == 1 {
return ""
}
modelarts.InitMultiNode()
var isServerNumValid = false
if modelarts.MultiNodeConfig != nil {
for _, info := range modelarts.MultiNodeConfig.Info {
if isInOrg, _ := models.IsOrganizationMemberByOrgName(info.Org, userId); isInOrg {
if isInNodes(info.Node, serverNum) {
isServerNumValid = true
break
}

}
}
}
if isServerNumValid {
return ""
} else {
return "repo.modelarts.no_node_right"
}
}
func checkInferenceJobMultiNode(userId int64, serverNum int) string {
if serverNum == 1 {
return ""
}

return "repo.modelarts.no_node_right"

}

func isInNodes(nodes []int, num int) bool {
for _, node := range nodes {
if node == num {
return true
}
}
return false

}

func getUserCommand(engineId int, req *modelarts.GenerateTrainJobReq) (string, string) {
userImageUrl := ""
userCommand := ""
@@ -1378,6 +1474,13 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ
ctx.Data["PageIsTrainJob"] = true
var jobID = ctx.Params(":jobid")

errStr := checkMultiNode(ctx.User.ID, form.WorkServerNumber)
if errStr != "" {
versionErrorDataPrepare(ctx, form)
ctx.RenderWithErr(ctx.Tr(errStr), tplModelArtsTrainJobVersionNew, &form)
return
}

count, err := models.GetCloudbrainTrainJobCountByUserID(ctx.User.ID)
if err != nil {
log.Error("GetCloudbrainTrainJobCountByUserID failed:%v", err, ctx.Data["MsgID"])
@@ -1723,10 +1826,6 @@ func paramCheckCreateTrainJob(form auth.CreateModelArtsTrainJobForm) error {
return errors.New("启动文件必须是python文件")
}

if form.WorkServerNumber > 2 || form.WorkServerNumber < 1 {
log.Error("the WorkServerNumber(%d) must be in (1,2)", form.WorkServerNumber)
return errors.New("计算节点数必须在1-2之间")
}
if form.BranchName == "" {
log.Error("the branch must not be null!", form.BranchName)
return errors.New("代码分支不能为空!")
@@ -1832,7 +1931,7 @@ func TrainJobShow(ctx *context.Context) {
} else {
VersionListTasks[i].Parameters = ""
}
datasetList = append(datasetList, GetCloudBrainDataSetInfo(task.Uuid, false))
datasetList = append(datasetList, GetCloudBrainDataSetInfo(task.Uuid, task.DatasetName, false))
VersionListTasks[i].CanDel = cloudbrain.CanDeleteJob(ctx, &task.Cloudbrain)
VersionListTasks[i].CanModify = cloudbrain.CanModifyJob(ctx, &task.Cloudbrain)

@@ -2030,6 +2129,13 @@ func InferenceJobCreate(ctx *context.Context, form auth.CreateModelArtsInference
ckptUrl := "/" + form.TrainUrl + form.CkptName
log.Info("ckpt url:" + ckptUrl)

errStr := checkInferenceJobMultiNode(ctx.User.ID, form.WorkServerNumber)
if errStr != "" {
inferenceJobErrorNewDataPrepare(ctx, form)
ctx.RenderWithErr(ctx.Tr(errStr), tplModelArtsInferenceJobNew, &form)
return
}

count, err := models.GetCloudbrainInferenceJobCountByUserID(ctx.User.ID)
if err != nil {
log.Error("GetCloudbrainInferenceJobCountByUserID failed:%v", err, ctx.Data["MsgID"])
@@ -2264,7 +2370,7 @@ func checkModelArtsSpecialPool(ctx *context.Context, flavorCode string, jobType
if !isMatchPool {
isMatchSpec := false
if jobType == string(models.JobTypeDebug) {
for _, flavor := range modelarts.FlavorInfos.FlavorInfo {
for _, flavor := range setting.StFlavorInfo.FlavorInfo {
if flavor.Value == flavorCode {
isMatchSpec = true
break
@@ -2477,14 +2583,7 @@ func inferenceJobErrorNewDataPrepare(ctx *context.Context, form auth.CreateModel
return err
}
ctx.Data["engine_versions"] = versionInfos.Version

var flavorInfos modelarts.Flavor
if err = json.Unmarshal([]byte(setting.TrainJobFLAVORINFOS), &flavorInfos); err != nil {
ctx.ServerError("json.Unmarshal failed:", err)
return err
}
ctx.Data["flavor_infos"] = flavorInfos.Info
setSpecBySpecialPoolConfig(ctx, string(models.JobTypeInference))
prepareCloudbrainTwoInferenceSpecs(ctx)

configList, err := getConfigList(modelarts.PerPage, 1, modelarts.SortByCreateTime, "desc", "", modelarts.ConfigTypeCustom)
if err != nil {
@@ -2567,7 +2666,7 @@ func InferenceJobShow(ctx *context.Context) {
ctx.Data["displayJobName"] = task.DisplayJobName
ctx.Data["task"] = task
ctx.Data["canDownload"] = cloudbrain.CanModifyJob(ctx, task)
ctx.Data["datasetDownload"] = GetCloudBrainDataSetInfo(task.Uuid, false)
ctx.Data["datasetDownload"] = GetCloudBrainDataSetInfo(task.Uuid, task.DatasetName, false)
tempUids := []int64{}
tempUids = append(tempUids, task.UserID)
JobCreater, err := models.GetUserNamesByIDs(tempUids)


+ 1
- 3
routers/user/home.go View File

@@ -836,14 +836,12 @@ func Cloudbrains(ctx *context.Context) {
ctx.ServerError("Get job failed:", err)
return
}
models.LoadSpecs4CloudbrainInfo(ciTasks)
for i, task := range ciTasks {
ciTasks[i].CanDebug = true
ciTasks[i].CanDel = true
ciTasks[i].Cloudbrain.ComputeResource = task.ComputeResource
ciTasks[i].Cloudbrain.AiCenter = repo.GetCloudbrainAiCenter(task.Cloudbrain, ctx)
_, cardType, _ := repo.GetCloudbrainCardNumAndType(task.Cloudbrain)
ciTasks[i].Cloudbrain.CardType = cardType
ciTasks[i].Cloudbrain.Cluster = repo.GetCloudbrainCluster(task.Cloudbrain, ctx)

}


+ 13
- 2
services/cloudbrain/resource/resource_specification.go View File

@@ -438,8 +438,12 @@ func findCloudbrainOneSpecFromRemote(task *models.Cloudbrain) (*models.Specifica
var shmMB float32
if jobRes.Config.TaskRoles != nil && len(jobRes.Config.TaskRoles) > 0 {
shmMB = float32(jobRes.Config.TaskRoles[0].ShmMB) / 1024
if jobRes.Config.TaskRoles[0].ShmMB == 103600 {
shmMB = 100
} else if jobRes.Config.TaskRoles[0].ShmMB == 51800 {
shmMB = 50
}
}

opt := models.FindSpecsOptions{
ComputeResource: task.ComputeResource,
Cluster: models.OpenICluster,
@@ -538,6 +542,12 @@ func findCloudbrainOneSpecFromConfig(task *models.Cloudbrain) (*models.Specifica
task.ComputeResource = models.GPU
}

shareMemMiB := float32(specConfig.ShareMemMiB) / 1024
if specConfig.ShareMemMiB == 103600 {
shareMemMiB = 100
} else if specConfig.ShareMemMiB == 51800 {
shareMemMiB = 50
}
opt := models.FindSpecsOptions{
JobType: models.JobType(task.JobType),
ComputeResource: task.ComputeResource,
@@ -550,7 +560,7 @@ func findCloudbrainOneSpecFromConfig(task *models.Cloudbrain) (*models.Specifica
UseCpuCores: true,
MemGiB: float32(specConfig.MemMiB) / 1024,
UseMemGiB: true,
ShareMemGiB: float32(specConfig.ShareMemMiB) / 1024,
ShareMemGiB: shareMemMiB,
UseShareMemGiB: true,
RequestAll: true,
}
@@ -639,5 +649,6 @@ func InitQueueAndSpec(opt models.FindSpecsOptions, aiCenterName string, remark s
GPUMemGiB: opt.GPUMemGiB,
ShareMemGiB: opt.ShareMemGiB,
Status: models.SpecOffShelf,
IsAvailable: true,
})
}

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

@@ -1,4 +1,5 @@
{{template "base/head" .}}
<script src="{{StaticUrlPrefix}}/js/specsuse.js?v={{MD5 AppVer}}" type="text/javascript"></script>
<!-- 弹窗 -->
<div id="mask">
<div id="loadingPage">
@@ -175,10 +176,17 @@
</div>
<!-- XPU类型 -->
<div class="one wide column text center nowrap" style="width:8% !important;">
<span style="font-size: 12px;" title="{{.CardType}}">
{{if .CardType}}{{.CardType}}{{else}}--{{end}}
</span>
</div>
<span style="font-size: 12px;" title="" class="card_type_{{.DisplayJobName}}_{{$JobID}}"></span>
</div>
<script>
(function(){
var spec = {{.Spec}} || {};
var cardType = getListValueWithKey(ACC_CARD_TYPE, spec.AccCardType) || '--';
var spanEl = document.querySelector('.card_type_{{.DisplayJobName}}_{{$JobID}}');
spanEl.setAttribute('title', cardType);
spanEl.innerText = cardType;
})();
</script>
<!-- 创建者 -->
<div class="one wide column text center nowrap" style="width:4% !important;">
{{if .User.Name}}


+ 1
- 1
templates/custom/wait_count_train.tmpl View File

@@ -18,7 +18,7 @@
></i>
<span id="gpu-nums" style="font-size: 12px"
>{{.ctx.i18n.Tr "repo.wait_count_start"}}
{{if .type}}
{{if .ctx.QueuesDetail}}
{{ $gpuQueue }}
{{else}}
{{.ctx.WaitCount}}


+ 11
- 4
templates/repo/cloudbrain/benchmark/new.tmpl View File

@@ -130,7 +130,7 @@
<div class="required min_title inline field" style="margin-top:2rem;">
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "cloudbrain.resource_specification"}}</label>
<select id="__specs__" class="ui search dropdown width48"
placeholder="{{.i18n.Tr "cloudbrain.select_specification"}}" style='width:385px'
placeholder="{{.i18n.Tr "cloudbrain.select_specification"}}" style='width:385px' ovalue="{{.spec_id}}"
{{if .CloudBrainPaySwitch}}blance="{{.PointAccount.Balance}}"{{end}}
name="spec_id">
</select>
@@ -202,7 +202,7 @@
<div class="required unite inline min_title fields" style="width: 90%;margin-left: 5.7rem;">&nbsp;
<div class="required eight wide field">
<label style="font-weight: normal;white-space: nowrap;">{{.i18n.Tr "repo.cloudbrain.benchmark.evaluate_type"}}</label>
<select class="ui fluid selection search dropdown" id="benchmark_types_id"
name="benchmark_types_id">
{{range .benchmark_types}}
@@ -240,7 +240,7 @@
<div class="required min_title inline field">
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "cloudbrain.resource_specification"}}</label>
<select id="__specs__" class="ui search dropdown width48"
placeholder="{{.i18n.Tr "cloudbrain.select_specification"}}" style='width:385px'
placeholder="{{.i18n.Tr "cloudbrain.select_specification"}}" style='width:385px' ovalue="{{.spec_id}}"
{{if .CloudBrainPaySwitch}}blance="{{.PointAccount.Balance}}"{{end}}
name="spec_id">
</select>
@@ -345,6 +345,7 @@
}
}
}
var isValidate = false;
function validate() {
$('.ui.form')
.form({
@@ -368,12 +369,18 @@
}
]
},
spec_id: {
identifier: 'spec_id',
rules: [{ type: 'empty' }]
}
},
onSuccess: function () {
// $('.ui.page.dimmer').dimmer('show')
document.getElementById("mask").style.display = "block"
isValidate = true;
},
onFailure: function (e) {
isValidate = false;
return false;
}
})
@@ -395,4 +402,4 @@
shared_memory: {{$.i18n.Tr "cloudbrain.shared_memory"}},
});
})();
</script>
</script>

+ 39
- 15
templates/repo/cloudbrain/benchmark/show.tmpl View File

@@ -256,8 +256,9 @@
<div class="ui pointing secondary menu" style="border-bottom: 1px solid rgba(34,36,38,.15);">
<a class="active item"
data-tab="first{{$k}}">{{$.i18n.Tr "repo.modelarts.train_job.config"}}</a>
<a class="item" data-tab="second{{$k}}"
onclick="loadLog({{.VersionName}})">{{$.i18n.Tr "repo.modelarts.log"}}</a>
<a class="item log_bottom" data-tab="second{{$k}}"
data-version="{{.VersionName}}">{{$.i18n.Tr "repo.modelarts.log"}}</a>
</div>
<div class="ui tab active" data-tab="first{{$k}}">
<div style="padding-top: 10px;">
@@ -524,19 +525,42 @@
</div>
<div class="ui tab" data-tab="second{{$k}}">
<div>
<div class="ui message message{{.VersionName}}" style="display: none;">
<div id="header"></div>
</div>
<div class="ui attached log" id="log{{.VersionName}}"
style="height: 300px !important; overflow: auto;">
<input type="hidden" name="end_line" value>
<input type="hidden" name="start_line" value>
<pre id="log_file{{.VersionName}}"></pre>
</div>

</div>

</div>
<a id="{{.VersionName}}-log-down"
class='{{if $.canDownload}}ti-download-file{{else}}disabled{{end}}'
href="/api/v1/repos/{{$.RepoRelPath}}/cloudbrain/{{.ID}}/download_log_file">
<i class="ri-download-cloud-2-line"></i>
<span style="margin-left: 0.3rem;">{{$.i18n.Tr "repo.modelarts.download_log"}}</span>
</a>
</div>
<div
style="position: relative;border: 1px solid rgba(0,0,0,.2);padding: 0 10px;margin-top: 10px;">
<span>
<a title="滚动到顶部" style="position: absolute; right: -32px;cursor: pointer;"
class="log_top" data-version="{{.VersionName}}"><i class="icon-to-top"></i></a>
</span>
<span class="log-info-{{.VersionName}}">
<a title="滚动到底部" style="position: absolute; bottom: 10px;right: -32px;cursor: pointer;"
class="log_bottom" data-version="{{.VersionName}}"><i
class="icon-to-bottom"></i></a>
</span>
<div class="ui message message{{.VersionName}}" style="display: none;">
<div id="header"></div>
</div>
<div class="ui attached log log-scroll" id="log{{.VersionName}}" data-version="{{.VersionName}}"
style="height: 300px !important; overflow: auto;">
<div class="ui inverted active dimmer">
<div class="ui loader"></div>
</div>
<input type="hidden" name="end_line" value>
<input type="hidden" name="start_line" value>
<pre id="log_file{{.VersionName}}"></pre>
</div>
</div>
</div>

</div>
</div>


+ 9
- 1
templates/repo/cloudbrain/inference/new.tmpl View File

@@ -254,7 +254,7 @@
</div>-->
<div class="required min_title inline field">
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "cloudbrain.resource_specification"}}</label>
<select id="__specs__" class="ui search dropdown width48" placeholder="{{.i18n.Tr "cloudbrain.select_specification"}}" name="spec_id" {{if .CloudBrainPaySwitch}}blance="{{.PointAccount.Balance}}"{{end}}>
<select id="__specs__" class="ui search dropdown width48" placeholder="{{.i18n.Tr "cloudbrain.select_specification"}}" ovalue="{{.spec_id}}" name="spec_id" {{if .CloudBrainPaySwitch}}blance="{{.PointAccount.Balance}}"{{end}}>
</select>
{{if .CloudBrainPaySwitch}}
<div class="cloudbrain_resource_spec_blance_tip width48" style="padding:0 5px;margin:6px 0;margin-left:155px;font-size:12px;">
@@ -452,6 +452,8 @@
msg = JSON.stringify(msg)
$('#store_run_para').val(msg)
}

var isValidate = false;
function validate(){
$('.ui.form')
.form({
@@ -505,12 +507,18 @@
type: 'empty',
}
]
},
spec_id: {
identifier: 'spec_id',
rules: [{ type: 'empty' }]
}
},
onSuccess: function(){
document.getElementById("mask").style.display = "block"
isValidate = true;
},
onFailure: function(e){
isValidate = false;
return false;
}
})


+ 49
- 5
templates/repo/cloudbrain/inference/show.tmpl View File

@@ -228,7 +228,7 @@
</h4>
{{with .task}}
<div class="ui accordion border-according" id="accordion{{.VersionName}}"
data-repopath="{{$.RepoRelPath}}/cloudbrain/inference-job" data-jobid="{{.JobID}}" data-version="{{.VersionName}}">
data-repopath="{{$.RepoRelPath}}/cloudbrain" data-jobid="{{.ID}}" data-version="{{.VersionName}}">
<input type="hidden" id="jobId_input" name="jobId_input" value="{{.JobID}}">
<div class="active title padding0">
<div class="according-panel-heading">
@@ -264,7 +264,8 @@
data-tab="first">{{$.i18n.Tr "repo.modelarts.train_job.config"}}</a>
<a class="item" data-tab="second"
onclick="javascript:parseInfo()">{{$.i18n.Tr "repo.cloudbrain.runinfo"}}</a>
<a class="item log_bottom" data-tab="third"
data-version="{{.VersionName}}">{{$.i18n.Tr "repo.modelarts.log"}}</a>
<a class="item load-model-file" data-tab="four"
data-gpu-flag="true" data-download-flag="{{$.canDownload}}" data-path="{{$.RepoLink}}/cloudbrain/inference-job/{{.JobID}}/result_list" data-version="{{.VersionName}}" data-parents="" data-filename="" data-init="init" >{{$.i18n.Tr "repo.model_download"}}</a>
</div>
@@ -496,7 +497,13 @@
<tbody>
{{range $m ,$n := $.datasetDownload}}
<tr>
<td style="word-wrap: break-word;word-break: break-all;"><a href="{{.RepositoryLink}}" target="_blank">{{.DatasetName}}</a></td>
<td style="word-wrap: break-word;word-break: break-all;">
{{if eq .IsDelete true}}
{{.DatasetName}}({{$.i18n.Tr "dataset.file_deleted"}})
{{else}}
<a href="{{.RepositoryLink}}" target="_blank">{{.DatasetName}}</a>
{{end}}
</td>
</tr>
{{end}}
@@ -514,7 +521,7 @@
<div class="ui message message{{.VersionName}}" style="display: none;">
<div id="header"></div>
</div>
<div class="ui attached log" id="log{{.VersionName}}"
<div class="ui attached"
style="height: 390px !important; overflow: auto;">
<input type="hidden" id="json_value" value="{{$.result.JobStatus.AppExitDiagnostics}}">
<input type="hidden" id="ExitDiagnostics" value="{{$.ExitDiagnostics}}">
@@ -527,7 +534,44 @@

</div>

<div class="ui tab" data-tab="third">
<div>
<a id="{{.VersionName}}-log-down"
class='{{if $.canDownload}}ti-download-file{{else}}disabled{{end}}'
href="/api/v1/repos/{{$.RepoRelPath}}/cloudbrain/{{.ID}}/download_log_file">
<i class="ri-download-cloud-2-line"></i>
<span style="margin-left: 0.3rem;">{{$.i18n.Tr "repo.modelarts.download_log"}}</span>
</a>
</div>
<div
style="position: relative;border: 1px solid rgba(0,0,0,.2);padding: 0 10px;margin-top: 10px;">
<span>
<a title="滚动到顶部" style="position: absolute; right: -32px;cursor: pointer;"
class="log_top" data-version="{{.VersionName}}"><i class="icon-to-top"></i></a>
</span>
<span class="log-info-{{.VersionName}}">
<a title="滚动到底部" style="position: absolute; bottom: 10px;right: -32px;cursor: pointer;"
class="log_bottom" data-version="{{.VersionName}}"><i
class="icon-to-bottom"></i></a>
</span>
<div class="ui message message{{.VersionName}}" style="display: none;">
<div id="header"></div>
</div>
<div class="ui attached log log-scroll" id="log{{.VersionName}}" data-version="{{.VersionName}}"
style="height: 300px !important; overflow: auto;">
<div class="ui inverted active dimmer">
<div class="ui loader"></div>
</div>
<input type="hidden" name="end_line" value>
<input type="hidden" name="start_line" value>
<pre id="log_file{{.VersionName}}"></pre>
</div>
</div>
</div>

<div class="ui tab" data-tab="four">
<input type="hidden" name="model{{.VersionName}}" value="-1">


+ 23
- 15
templates/repo/cloudbrain/new.tmpl View File

@@ -1,6 +1,6 @@
{{template "base/head" .}}
<style>
/* 遮罩层css效果图 */
.inline.required.field.cloudbrain_benchmark {
display: none;
@@ -13,7 +13,7 @@
.inline.required.field.cloudbrain_brainscore {
display: none;
}

</style>

@@ -55,8 +55,8 @@
d="M3 2.992C3 2.444 3.445 2 3.993 2h16.014a1 1 0 0 1 .993.992v18.016a.993.993 0 0 1-.993.992H3.993A1 1 0 0 1 3 21.008V2.992zM19 11V4H5v7h14zm0 2H5v7h14v-7zM9 6h6v2H9V6zm0 9h6v2H9v-2z" />
</svg>
Ascend NPU</a>
</div>
</div>
</div>
</div>
<div class="inline field">
<label></label>
{{template "custom/task_wait_count" .}}
@@ -111,7 +111,7 @@
{{end}}
{{end}}
</select>
</div>
</div>
<!--<div class="inline required field">
<label>{{.i18n.Tr "cloudbrain.gpu_type"}}</label>
<select id="cloudbrain_gpu_type" class="ui search dropdown gpu-type" placeholder="选择GPU类型"
@@ -128,7 +128,7 @@
<div id="select-multi-dataset">

</div>
<!--<div class="inline required field">
<label>{{.i18n.Tr "cloudbrain.resource_specification"}}</label>
<select id="cloudbrain_resource_spec" class="ui search dropdown"
@@ -141,11 +141,11 @@
{{end}}
</select>
</div>-->
<div class="inline required field">
<label>{{.i18n.Tr "cloudbrain.resource_specification"}}</label>
<select id="__specs__" class="ui search dropdown"
placeholder="{{.i18n.Tr "cloudbrain.select_specification"}}" style='width:385px'
placeholder="{{.i18n.Tr "cloudbrain.select_specification"}}" style='width:385px' ovalue="{{.spec_id}}"
{{if .CloudBrainPaySwitch}}blance="{{.PointAccount.Balance}}"{{end}}
name="spec_id">
</select>
@@ -218,10 +218,11 @@
context.value = ''
$(".icon.icons").css("visibility", "hidden")
}
var isValidate = false;
function validate(){
$('.ui.form').form({
on: 'blur',
fields: {
fields: {
display_job_name:{
identifier : 'display_job_name',
rules: [
@@ -229,11 +230,17 @@
type: 'regExp[/^[a-z0-9][a-z0-9-_]{1,34}[a-z0-9-]$/]',
}
]
},
},
spec_id: {
identifier: 'spec_id',
rules: [{ type: 'empty' }]
}
},
onSuccess: function(){
onSuccess: function(){
isValidate = true;
},
onFailure: function(e){
isValidate = false;
return false;
}
})
@@ -241,6 +248,7 @@
validate();
let createFlag = false
form.onsubmit = function (e) {
if (!isValidate) return false;
if(createFlag) return false
let value_task = $("input[name='display_job_name']").val()
let value_image = $("input[name='image']").val()
@@ -264,7 +272,7 @@
if (document.readyState === "complete") {
document.getElementById("mask").style.display = "none"
}
}

$('#cloudbrain_benchmark_category')
@@ -301,14 +309,14 @@
}
})
})
$('.ui.green.button').click(function () {
if (!$('input[name="isBranches"]').val()) {
return false
}
selected_value = $("#cloudbrain_benchmark_category").val()
$('#store_category').attr("value", selected_value)
validate();
})

;(function() {
@@ -322,4 +330,4 @@
shared_memory: {{$.i18n.Tr "cloudbrain.shared_memory"}},
});
})();
</script>
</script>

+ 7
- 1
templates/repo/cloudbrain/show.tmpl View File

@@ -494,7 +494,13 @@
<tbody>
{{range $m ,$n := $.datasetDownload}}
<tr>
<td style="word-wrap: break-word;word-break: break-all;"><a href="{{.RepositoryLink}}" target="_blank">{{.DatasetName}}</a></td>
<td style="word-wrap: break-word;word-break: break-all;">
{{if eq .IsDelete true}}
{{.DatasetName}}({{$.i18n.Tr "dataset.file_deleted"}})
{{else}}
<a href="{{.RepositoryLink}}" target="_blank">{{.DatasetName}}</a>
{{end}}
</td>
</tr>
{{end}}


+ 8
- 1
templates/repo/cloudbrain/trainjob/new.tmpl View File

@@ -258,7 +258,7 @@

<div class="required min_title inline field">
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "cloudbrain.resource_specification"}}</label>
<select id="__specs__" class="ui dropdown width48" placeholder="{{.i18n.Tr "cloudbrain.select_specification"}}"
<select id="__specs__" class="ui dropdown width48" placeholder="{{.i18n.Tr "cloudbrain.select_specification"}}" ovalue="{{.spec_id}}"
{{if .CloudBrainPaySwitch}}blance="{{.PointAccount.Balance}}"{{end}}
name="spec_id">
</select>
@@ -365,6 +365,7 @@
$('select.dropdown')
.dropdown();

var isValidate = false;
function validate() {
$('.ui.form')
.form({
@@ -410,13 +411,19 @@
type: 'empty',
}
]
},
spec_id: {
identifier: 'spec_id',
rules: [{ type: 'empty' }]
}
},
onSuccess: function () {
// $('.ui.page.dimmer').dimmer('show')
document.getElementById("mask").style.display = "block"
isValidate = true;
},
onFailure: function (e) {
isValidate = false;
return false;
}
})


+ 8
- 2
templates/repo/cloudbrain/trainjob/show.tmpl View File

@@ -460,7 +460,13 @@
<tbody>
{{range $m ,$n := $.datasetDownload}}
<tr>
<td style="word-wrap: break-word;word-break: break-all;"><a href="{{.RepositoryLink}}" target="_blank">{{.DatasetName}}</a></td>
<td style="word-wrap: break-word;word-break: break-all;">
{{if eq .IsDelete true}}
{{.DatasetName}}({{$.i18n.Tr "dataset.file_deleted"}})
{{else}}
<a href="{{.RepositoryLink}}" target="_blank">{{.DatasetName}}</a>
{{end}}
</td>
</tr>
{{end}}
@@ -590,7 +596,7 @@
<input type="hidden" name="trainTaskCreate" value="true">

<div class="required inline field">
<label>{{.i18n.Tr "repo.model.manage.createtrainjob"}}</label>
<label>{{.i18n.Tr "repo.modelarts.train_job"}}</label>
<input type="hidden" class="width83" id="JobId" name="JobId" readonly required>
<input type="hidden" id="VersionName" name="VersionName" value="V0001">
<input style="width: 45%;" id="JobName" readonly required>


+ 9
- 2
templates/repo/grampus/trainjob/gpu/new.tmpl View File

@@ -106,7 +106,7 @@
<path d="M3 2.992C3 2.444 3.445 2 3.993 2h16.014a1 1 0 0 1 .993.992v18.016a.993.993 0 0 1-.993.992H3.993A1 1 0 0 1 3 21.008V2.992zM19 11V4H5v7h14zm0 2H5v7h14v-7zM9 6h6v2H9V6zm0 9h6v2H9v-2z"/>
</svg>
Ascend NPU</a>
</div>
</div>
</div>
<div class="min_title inline field" style="margin-top:-10px;">
<label class="label-fix-width" style="font-weight: normal;"></label>
@@ -206,7 +206,7 @@
</div>-->
<div class="required min_title inline field" id="flavor_name">
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.standard"}}</label>
<select class="ui dropdown width48" id="__specs__" style='width:385px' name="spec_id" {{if .CloudBrainPaySwitch}}blance="{{.PointAccount.Balance}}"{{end}}></select>
<select class="ui dropdown width48" id="__specs__" style='width:385px' name="spec_id" ovalue="{{.spec_id}}" {{if .CloudBrainPaySwitch}}blance="{{.PointAccount.Balance}}"{{end}}></select>
{{if .CloudBrainPaySwitch}}
<div class="cloudbrain_resource_spec_blance_tip width48" style="padding:0 5px;margin:6px 0;margin-left:155px;font-size:12px;">
<span>{{$.i18n.Tr "points.balance_of_points"}}<span style="color:red;margin: 0 3px">{{.PointAccount.Balance}}</span>{{$.i18n.Tr "points.points"}}</span><span>{{$.i18n.Tr "points.expected_time"}}<span style="color:red;margin: 0 3px" class="can-use-time"></span>{{$.i18n.Tr "points.hours"}}</span>
@@ -305,6 +305,7 @@
$('select.dropdown')
.dropdown();

var isValidate = false;
function validate(){
$('.ui.form')
.form({
@@ -351,13 +352,19 @@
type : 'integer[1..25]',
}
]
},
spec_id: {
identifier: 'spec_id',
rules: [{ type: 'empty' }]
}
},
onSuccess: function(){
// $('.ui.page.dimmer').dimmer('show')
document.getElementById("mask").style.display = "block"
isValidate = true;
},
onFailure: function(e){
isValidate = false;
return false;
}
})


+ 8
- 1
templates/repo/grampus/trainjob/npu/new.tmpl View File

@@ -218,7 +218,7 @@
</div>-->
<div class="required min_title inline field" id="flavor_name">
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.standard"}}</label>
<select class="ui dropdown width48" id="__specs__" style='width:385px' name="spec_id" {{if .CloudBrainPaySwitch}}blance="{{.PointAccount.Balance}}"{{end}}></select>
<select class="ui dropdown width48" id="__specs__" style='width:385px' name="spec_id" ovalue="{{.spec_id}}" {{if .CloudBrainPaySwitch}}blance="{{.PointAccount.Balance}}"{{end}}></select>
{{if .CloudBrainPaySwitch}}
<div class="cloudbrain_resource_spec_blance_tip width48" style="padding:0 5px;margin:6px 0;margin-left:155px;font-size:12px;">
<span>{{$.i18n.Tr "points.balance_of_points"}}<span style="color:red;margin: 0 3px">{{.PointAccount.Balance}}</span>{{$.i18n.Tr "points.points"}}</span><span>{{$.i18n.Tr "points.expected_time"}}<span style="color:red;margin: 0 3px" class="can-use-time"></span>{{$.i18n.Tr "points.hours"}}</span>
@@ -331,6 +331,7 @@
$('select.dropdown')
.dropdown();

var isValidate = false;
function validate(){
$('.ui.form')
.form({
@@ -368,13 +369,19 @@
type : 'integer[1..25]',
}
]
},
spec_id: {
identifier: 'spec_id',
rules: [{ type: 'empty' }]
}
},
onSuccess: function(){
// $('.ui.page.dimmer').dimmer('show')
document.getElementById("mask").style.display = "block"
isValidate = true;
},
onFailure: function(e){
isValidate = false;
return false;
}
})


+ 7
- 2
templates/repo/grampus/trainjob/show.tmpl View File

@@ -417,7 +417,12 @@
<td class="ti-text-form-content">
<div class="text-span text-span-w">
{{range $m ,$n := $.datasetDownload}}
<a href="{{.RepositoryLink}}" target="_blank">{{.DatasetName}}</a>
{{if eq .IsDelete true}}
{{.DatasetName}}({{$.i18n.Tr "dataset.file_deleted"}})
{{else}}
<a href="{{.RepositoryLink}}" target="_blank">{{.DatasetName}}</a>
{{end}}
{{end}}
</div>
</td>
@@ -549,7 +554,7 @@
<input type="hidden" name="trainTaskCreate" value="true">

<div class="required inline field">
<label>{{.i18n.Tr "repo.model.manage.createtrainjob"}}</label>
<label>{{.i18n.Tr "repo.modelarts.train_job"}}</label>
<input type="hidden" class="width83" id="JobId" name="JobId" readonly required>
<input type="hidden" id="VersionName" name="VersionName" value="V0001">
<input style="width: 45%;" id="JobName" readonly required>


+ 9
- 1
templates/repo/modelarts/inferencejob/new.tmpl View File

@@ -275,7 +275,7 @@
</div>-->
<div class="required min_title inline field" id="flaver_name">
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.standard"}}</label>
<select class="ui dropdown width48" id="__specs__" name="spec_id" {{if .CloudBrainPaySwitch}}blance="{{.PointAccount.Balance}}"{{end}}></select>
<select class="ui dropdown width48" id="__specs__" name="spec_id" ovalue="{{.spec_id}}" {{if .CloudBrainPaySwitch}}blance="{{.PointAccount.Balance}}"{{end}}></select>
{{if .CloudBrainPaySwitch}}
<div class="cloudbrain_resource_spec_blance_tip width48" style="padding:0 5px;margin:6px 0;margin-left:155px;font-size:12px;">
<span>{{$.i18n.Tr "points.balance_of_points"}}<span style="color:red;margin: 0 3px">{{.PointAccount.Balance}}</span>{{$.i18n.Tr "points.points"}}</span><span>{{$.i18n.Tr "points.expected_time"}}<span style="color:red;margin: 0 3px" class="can-use-time"></span>{{$.i18n.Tr "points.hours"}}</span>
@@ -474,6 +474,8 @@
$("input#ai_engine_name").val(name1)
$("input#ai_flaver_name").val(name2)
}

var isValidate = false;
function validate(){
$('.ui.form')
.form({
@@ -527,12 +529,18 @@
type: 'empty',
}
]
},
spec_id: {
identifier: 'spec_id',
rules: [{ type: 'empty' }]
}
},
onSuccess: function(){
document.getElementById("mask").style.display = "block"
isValidate = true;
},
onFailure: function(e){
isValidate = false;
return false;
}
})


+ 8
- 1
templates/repo/modelarts/inferencejob/show.tmpl View File

@@ -439,7 +439,14 @@ td, th {
<tbody>
{{range $m ,$n := $.datasetDownload}}
<tr>
<td style="word-wrap: break-word;word-break: break-all;"><a href="{{.RepositoryLink}}" target="_blank">{{.DatasetName}}</a></td>
<td style="word-wrap: break-word;word-break: break-all;">
{{if eq .IsDelete true}}
{{.DatasetName}}({{$.i18n.Tr "dataset.file_deleted"}})
{{else}}
<a href="{{.RepositoryLink}}" target="_blank">{{.DatasetName}}</a>
{{end}}
</td>
</tr>
{{end}}


+ 14
- 5
templates/repo/modelarts/notebook/new.tmpl View File

@@ -79,7 +79,7 @@
</div>-->
<div class="inline required field">
<label>{{.i18n.Tr "cloudbrain.specification"}}</label>
<select id="__specs__" class="ui search dropdown"
<select id="__specs__" class="ui search dropdown" ovalue="{{.spec_id}}"
{{if .CloudBrainPaySwitch}}blance="{{.PointAccount.Balance}}"{{end}}
placeholder="{{.i18n.Tr "cloudbrain.select_specification"}}" style='width:385px' name="spec_id"></select>
{{if .CloudBrainPaySwitch}}
@@ -91,6 +91,7 @@
</span>
</div>
{{end}}
<select id="__specs__" class="ui search dropdown" placeholder="{{.i18n.Tr "cloudbrain.select_specification"}}" style='width:385px' name="spec_id" ovalue="{{.spec_id}}"></select>
</div>
<!--<div class="inline required field">
<label>数据集存放路径</label>
@@ -120,10 +121,11 @@

$('#messageInfo').css('display','none')

var isValidate = false;
function validate(){
$('.ui.form').form({
on: 'blur',
fields: {
fields: {
display_job_name:{
identifier : 'display_job_name',
rules: [
@@ -131,11 +133,17 @@
type: 'regExp[/^[a-z0-9][a-z0-9-_]{1,34}[a-z0-9-]$/]',
}
]
},
},
spec_id: {
identifier: 'spec_id',
rules: [{ type: 'empty' }]
}
},
onSuccess: function(){
onSuccess: function(){
isValidate = true;
},
onFailure: function(e){
isValidate = false;
return false;
}
})
@@ -143,7 +151,8 @@
validate();
let createFlag = false
form.onsubmit = function(e){
if(createFlag) return false
if(!isValidate) return false;
if(createFlag) return false;
let value_task = $("input[name='display_job_name']").val()
let re = /^[a-z0-9][a-z0-9-_]{1,34}[a-z0-9-]$/
let flag = re.test(value_task)


+ 8
- 1
templates/repo/modelarts/notebook/show.tmpl View File

@@ -437,7 +437,14 @@
<tbody>
{{range $.datasetDownload}}
<tr>
<td style="word-wrap: break-word;word-break: break-all;"><a href="{{.RepositoryLink}}" target="_blank">{{.DatasetName}}</a></td>
<td style="word-wrap: break-word;word-break: break-all;">
{{if eq .IsDelete true}}
{{.DatasetName}}({{$.i18n.Tr "dataset.file_deleted"}})
{{else}}
<a href="{{.RepositoryLink}}" target="_blank">{{.DatasetName}}</a>
{{end}}
</td>
<td style="word-wrap: break-word;word-break: break-all;">{{.DatasetDownloadLink}}</td>
<td class="center aligned"><a class="ui poping up clipboard" id="clipboard-btn-dataset" data-original="{{$.i18n.Tr "repo.copy_link"}}" data-success="{{$.i18n.Tr "repo.copy_link_success"}}" data-error="{{$.i18n.Tr "repo.copy_link_error"}}" data-content="{{$.i18n.Tr "repo.copy_link"}}" data-variation="inverted tiny" data-clipboard-text="{{.DatasetDownloadLink}}">{{$.i18n.Tr "dataset.download_copy"}}</a></td>
</tr>


+ 26
- 3
templates/repo/modelarts/trainjob/new.tmpl View File

@@ -109,7 +109,7 @@
d="M3 2.992C3 2.444 3.445 2 3.993 2h16.014a1 1 0 0 1 .993.992v18.016a.993.993 0 0 1-.993.992H3.993A1 1 0 0 1 3 21.008V2.992zM19 11V4H5v7h14zm0 2H5v7h14v-7zM9 6h6v2H9V6zm0 9h6v2H9v-2z" />
</svg>
Ascend NPU</a>
</div>
</div>
</div>
<div class="min_title inline field" style="margin-top:-10px;">
<label class="label-fix-width" style="font-weight: normal;"></label>
@@ -283,7 +283,7 @@
</div>-->
<div class="required inline min_title field" id="flaver_name">
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.standard"}}</label>
<select class="ui dropdown width48" id="__specs__" name="spec_id" {{if .CloudBrainPaySwitch}}blance="{{.PointAccount.Balance}}"{{end}}></select>
<select class="ui dropdown width48" id="__specs__" name="spec_id" ovalue="{{.spec_id}}" {{if .CloudBrainPaySwitch}}blance="{{.PointAccount.Balance}}"{{end}}></select>
{{if .CloudBrainPaySwitch}}
<div class="cloudbrain_resource_spec_blance_tip width48" style="padding:0 5px;margin:6px 0;margin-left:155px;font-size:12px;">
<span>{{$.i18n.Tr "points.balance_of_points"}}<span style="color:red;margin: 0 3px">{{.PointAccount.Balance}}</span>{{$.i18n.Tr "points.points"}}</span><span>{{$.i18n.Tr "points.expected_time"}}<span style="color:red;margin: 0 3px" class="can-use-time"></span>{{$.i18n.Tr "points.hours"}}</span>
@@ -303,8 +303,24 @@
id="trainjob_work_server_num" tabindex="3" autofocus required maxlength="255" value="1"
readonly>
<div class="field" id="trainjob_work_server_num_select" name="work_server_number_select">
<select class="ui dropdown width" style='width: 100%;' name="work_server_id">
<select class="ui dropdown width" style='width: 100%;' name="work_server_id">
{{if .WorkNode}}
{{range .WorkNode}}

{{if $.work_server_number}}
{{if eq . $.work_server_number }}
<option name="server_id" selected value="{{.}}">{{.}}</option>
{{else}}
<option name="server_id" value="{{.}}">{{.}}</option>
{{end}}
{{else}}
<option name="server_id" value="{{.}}">{{.}}</option>
{{end}}
{{end}}

{{else}}
<option name="server_id" value="1">1</option>
{{end}}
</select>
</div>

@@ -457,6 +473,7 @@
$('select.dropdown')
.dropdown();

var isValidate = false;
function validate() {
$('.ui.form')
.form({
@@ -494,13 +511,19 @@
type: 'integer[1..25]',
}
]
},
spec_id: {
identifier: 'spec_id',
rules: [{ type: 'empty' }]
}
},
onSuccess: function () {
// $('.ui.page.dimmer').dimmer('show')
document.getElementById("mask").style.display = "block"
isValidate = true;
},
onFailure: function (e) {
isValidate = false;
return false;
}
})


+ 8
- 2
templates/repo/modelarts/trainjob/show.tmpl View File

@@ -503,7 +503,13 @@
{{if eq $k $m}}
{{range $f ,$g := $n}}
<tr>
<td style="word-wrap: break-word;word-break: break-all;"><a href="{{.RepositoryLink}}" target="_blank">{{.DatasetName}}</a></td>
<td style="word-wrap: break-word;word-break: break-all;">
{{if eq .IsDelete true}}
{{.DatasetName}}({{$.i18n.Tr "dataset.file_deleted"}})
{{else}}
<a href="{{.RepositoryLink}}" target="_blank">{{.DatasetName}}</a>
{{end}}
</td>
</tr>
{{end}}
{{end}}
@@ -618,7 +624,7 @@

<div class="two inline fields ">
<div class="required ten wide field">
<label style="margin-left: -23px;">{{.i18n.Tr "repo.model.manage.createtrainjob"}}</label>
<label style="margin-left: -23px;">{{.i18n.Tr "repo.modelarts.train_job"}}</label>
<input type="hidden" class="width83" id="JobId" name="JobId" readonly required>
<input class="width83" id="JobName" readonly required>



+ 11
- 51
templates/repo/modelarts/trainjob/version_new.tmpl View File

@@ -72,7 +72,7 @@
{{end}}
<input type="hidden" id="ai_engine_name" name="engine_names" value="">
<input type="hidden" id="ai_flaver_name" name="flaver_names" value="">
<input type="hidden" id="display_job_name" name="display_job_name" value="{{.display_job_name}}">
<input type="hidden" id="display_job_name" name="display_job_name" value="{{.display_job_name}}">
<h4 class="unite title ui header ">{{.i18n.Tr "repo.modelarts.train_job.basic_info"}}:</h4>
<div class="required min_title inline field">
<label class="" style="font-weight: normal;">{{.i18n.Tr "cloudbrain.resource_cluster"}}</label>
@@ -107,7 +107,7 @@
d="M3 2.992C3 2.444 3.445 2 3.993 2h16.014a1 1 0 0 1 .993.992v18.016a.993.993 0 0 1-.993.992H3.993A1 1 0 0 1 3 21.008V2.992zM19 11V4H5v7h14zm0 2H5v7h14v-7zM9 6h6v2H9V6zm0 9h6v2H9v-2z" />
</svg>
Ascend NPU</a>
</div>
</div>
</div>
<div style="display: flex;align-items: center;margin-left: 156px;margin-top: -0.5rem;">
{{template "custom/task_wait_count" .}}
@@ -263,7 +263,7 @@
</div>-->
<div class="required unite min_title inline field" id="flaver_name">
<label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.standard"}}</label>
<select id="__specs__" class="ui dropdown width80" style='width:385px' name="spec_id" {{if .CloudBrainPaySwitch}}blance="{{.PointAccount.Balance}}"{{end}}></select>
<select id="__specs__" class="ui dropdown width80" style='width:385px' name="spec_id" ovalue="{{.spec_id}}" {{if .CloudBrainPaySwitch}}blance="{{.PointAccount.Balance}}"{{end}}></select>
{{if .CloudBrainPaySwitch}}
<div class="cloudbrain_resource_spec_blance_tip width80" style="padding:0 5px;margin:6px 0;margin-left:60px;font-size:12px;">
<span>{{$.i18n.Tr "points.balance_of_points"}}<span style="color:red;margin: 0 3px">{{.PointAccount.Balance}}</span>{{$.i18n.Tr "points.points"}}</span><span>{{$.i18n.Tr "points.expected_time"}}<span style="color:red;margin: 0 3px" class="can-use-time"></span>{{$.i18n.Tr "points.hours"}}</span>
@@ -440,53 +440,7 @@
$('select.dropdown')
.dropdown();

$('.ui.form')
.form({
on: 'blur',
inline:true,
fields: {
boot_file: {
identifier : 'boot_file',
rules: [
{
type: 'regExp[/.+\.py$/g]',
prompt : '启动文件必须为.py结尾'
}
]
},
job_name:{
identifier : 'job_name',
rules: [
{
type: 'regExp[/^[a-zA-Z0-9-_]{1,36}$/]',
prompt : '只包含大小写字母、数字、_和-,最长36个字符。'
}
]
},
display_job_name:{
identifier : 'display_job_name',
rules: [
{
type: 'regExp[/^[a-zA-Z0-9-_]{1,36}$/]',
prompt : '只包含大小写字母、数字、_和-,最长36个字符。'
}
]
},
attachment:{
identifier : 'attachment',
rules: [
{
type: 'empty',
prompt : '选择一个数据集'
}
]

},
},
})



var isValidate = false;
function validate(){
$('.ui.form')
.form({
@@ -530,12 +484,18 @@
]

},
spec_id: {
identifier: 'spec_id',
rules: [{ type: 'empty' }]
}
},
onSuccess: function(){
// $('.ui.page.dimmer').dimmer('show')
document.getElementById("mask").style.display = "block"
isValidate = true;
},
onFailure: function(e){
isValidate = false;
return false;
}
})
@@ -565,7 +525,7 @@
$("input#ai_flaver_name").val(name2)

}
validate()
$('.ui.create_train_job.green.button').click(function(e) {
get_name()


+ 2
- 2
templates/repo/modelmanage/convertIndex.tmpl View File

@@ -50,9 +50,9 @@
<div class="bgtask-content-header">{{$.i18n.Tr "repo.modelconvert.notcreate"}}</div>
<div class="bgtask-content">
{{if eq .MODEL_COUNT 0}}
<div class="bgtask-content-txt">{{$.i18n.Tr "repo.modelconvert.importfirst1"}}<a href="{{.RepoLink}}/modelmanage/show_model">{{$.i18n.Tr "repo.modelconvert.importfirst2"}}</a>{{$.i18n.Tr "repo.modelconvert.importfirst3"}}</div>
<div class="bgtask-content-txt">{{$.i18n.Tr "repo.modelconvert.importfirst1"}}<a href="{{.RepoLink}}/modelmanage/show_model">&nbsp;{{$.i18n.Tr "repo.modelconvert.importfirst2"}}&nbsp;</a>{{$.i18n.Tr "repo.modelconvert.importfirst3"}}</div>
{{end}}
<div class="bgtask-content-txt">{{$.i18n.Tr "repo.platform_instructions"}}</div>
<div class="bgtask-content-txt">{{$.i18n.Tr "repo.platform_instructions1"}}<a href="https://git.openi.org.cn/zeizei/OpenI_Learning">&nbsp;{{$.i18n.Tr "repo.platform_instructions2"}}&nbsp;</a>{{$.i18n.Tr "repo.platform_instructions3"}}</div>

</div>
</div>


+ 3
- 3
templates/repo/modelmanage/index.tmpl View File

@@ -71,9 +71,9 @@
{{end}}
{{if eq $.TRAIN_COUNT 0}}
<div class="bgtask-content-txt">{{$.i18n.Tr "repo.model.manage.createtrainjob_tip"}}<a
href="{{.RepoLink}}/modelarts/train-job">{{$.i18n.Tr "repo.model.manage.createtrainjob"}}</a></div>
href="{{.RepoLink}}/modelarts/train-job">&nbsp;{{$.i18n.Tr "repo.model.manage.createtrainjob"}}</a></div>
{{end}}
<div class="bgtask-content-txt">{{$.i18n.Tr "repo.platform_instructions"}}</a></div>
<div class="bgtask-content-txt">{{$.i18n.Tr "repo.platform_instructions1"}}<a href="https://git.openi.org.cn/zeizei/OpenI_Learning">&nbsp;{{$.i18n.Tr "repo.platform_instructions2"}}&nbsp;</a>{{$.i18n.Tr "repo.platform_instructions3"}}</div>

</div>
<div style="display: none;">
@@ -330,7 +330,7 @@
.modal({
centered: false,
onShow: function () {
$('#model_header').text("导入新模型")
$('#model_header').text({{.i18n.Tr "repo.model.manage.import_new_model"}})
$('input[name="Version"]').addClass('model_disabled')
$('.ui.dimmer').css({ "background-color": "rgb(136, 136, 136,0.7)" })
$("#job-name").empty()


+ 1
- 1
templates/repo/modelmanage/showinfo.tmpl View File

@@ -125,7 +125,7 @@
</td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.model.manage.createtrainjob"}}</td>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.modelarts.train_job"}}</td>
<td class="ti-text-form-content word-elipsis">
<a id="DisplayJobNameHref" class="title" style="font-size: 14px;" target="_blank">
<span id="DisplayJobName" class="fitted" style="width: 90%;vertical-align: middle;"></span>


+ 12
- 5
templates/user/dashboard/cloudbrains.tmpl View File

@@ -1,5 +1,6 @@
{{template "base/head" .}}
<!-- 提示框 -->
<script src="{{StaticUrlPrefix}}/js/specsuse.js?v={{MD5 AppVer}}" type="text/javascript"></script>
<div class="alert"></div>
<div class="explore users">
<div class="cloudbrain_debug" style="display: none;" data-debug="{{$.i18n.Tr "repo.debug"}}"
@@ -159,11 +160,17 @@
</div>
<!-- XPU类型 -->
<div class="one wide column text center nowrap" style="width:10% !important;">
<span style="font-size: 12px;" title="{{.CardType}}">
{{if .CardType}}{{.CardType}}{{else}}--{{end}}
</span>
</div>

<span style="font-size: 12px;" title="" class="card_type_{{.DisplayJobName}}_{{$JobID}}"></span>
</div>
<script>
(function(){
var spec = {{.Spec}} || {};
var cardType = getListValueWithKey(ACC_CARD_TYPE, spec.AccCardType) || '--';
var spanEl = document.querySelector('.card_type_{{.DisplayJobName}}_{{$JobID}}');
spanEl.setAttribute('title', cardType);
spanEl.innerText = cardType;
})();
</script>
<!-- 项目 -->
<div class="two wide column text center nowrap" style="width: 11%!important;">
<a href="{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}"


+ 2
- 1
web_src/js/components/Model.vue View File

@@ -197,11 +197,12 @@ export default {
this.getModelList()
},
showcreateVue(name,version,label){
let title= this.i18n.model_create_version_title;
$('.ui.modal.second')
.modal({
centered: false,
onShow:function(){
$('#model_header').text("创建模型新版本")
$('#model_header').text(title)
$('input[name="Name"]').addClass('model_disabled')
$('input[name="Name"]').attr('readonly','readonly')
$('input[name="modelSelectedFile"]').attr('readonly','readonly')


+ 1
- 1
web_src/js/components/dataset/referenceDataset.vue View File

@@ -248,7 +248,7 @@
>
<el-tabs v-model="activeName">
<el-tab-pane :label="i18n.public_dataset" name="first">
<el-row v-loading="loadingPublicPage">
<el-row v-loading="loadingPublicPage" style="min-height: 50px">
<el-checkbox-group
v-model="checkList"
style="font-size: 14px; line-height: 1"


+ 5
- 2
web_src/js/components/dataset/selectDataset.vue View File

@@ -546,7 +546,7 @@
>
{{ i18n.dataset_selected }}
</div>
<div style="flex: 1; margin-top: 1.5rem">
<div style="flex: 1; margin: 1.5rem 0; overflow-y: auto">
<el-checkbox-group v-model="checkList">
<el-checkbox
v-for="(item, index) in selectDatasetArray"
@@ -985,7 +985,10 @@ export default {
let hasSelectDatasetName = $(".cloudbrain-type")
.data("dataset-name")
.split(";");
if (this.hasSelectDatasetList.length !== 0) {
if (
this.hasSelectDatasetList.length !== 0 &&
hasSelectDatasetName[0] !== ""
) {
this.saveStatusList = this.hasSelectDatasetList;
this.checkList = hasSelectDatasetName;
this.hasSelectDatasetList.forEach((item, index) => {


+ 5
- 1
web_src/js/features/i18nVue.js View File

@@ -95,6 +95,8 @@ export const i18nVue = {
model_create_new_ver: "创建新版本",
model_download: "下载",
model_delete: "删除",
model_create_title: "导入新模型",
model_create_version_title: "创建模型新版本",
},
US: {
computer_vision: "computer vision",
@@ -152,7 +154,7 @@ export const i18nVue = {

dataset_instructions_for_use:
"Instructions for use: You can refer to OpenI AI Collaboration Platform ",
dataset_camp_course: " Newcomer Training Camp Course",
dataset_camp_course: " OpenI_Learning",
dataset_link_success: "Linked dataset succeeded!",
dataset_link_failed: "Linked dataset Failed!",
dataset_over_nums: "Linked over ? datasets!",
@@ -196,5 +198,7 @@ export const i18nVue = {
model_create_new_ver: "New Version",
model_download: "Download",
model_delete: "Delete",
model_create_title: "Import new model",
model_create_version_title: "Create a new version of the model",
},
};

+ 2
- 0
web_src/js/standalone/specsuse.js View File

@@ -22,11 +22,13 @@ window.renderSpecsSelect = (specsSel, data, showPoint, langObj) => {
specsSel.empty();
data = data || [];
showPoint = specsSel.attr('blance') ? true : false;
var oValue = specsSel.attr('ovalue');
for (var i = 0, iLen = data.length; i < iLen; i++) {
var spec = data[i];
var specStr = window.renderSpecStr(spec, showPoint, langObj);
specsSel.append(`<option name="spec_id" value="${spec.ID}" queueCode="${spec.QueueCode}" unitprice="${spec.UnitPrice}">${specStr}</option>`);
}
oValue && specsSel.val(oValue);
if (showPoint) {
specsSel.on('change', function (e) {
var cloudbrain_resource_spec_blance_tip_el = $('.cloudbrain_resource_spec_blance_tip');


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

@@ -10,7 +10,7 @@ export const JOB_TYPE = [{ k: 'DEBUG', v: i18n.t('debugTask') }, { k: 'TRAIN', v

// 资源管理
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: 'chendu', v: i18n.t('resourcesManagement.chenduCenter') }, { k: 'pclcci', v: i18n.t('resourcesManagement.pclcci') }, { k: 'hefei', v: i18n.t('resourcesManagement.hefeiCenter') }, { k: 'xuchang', v: i18n.t('resourcesManagement.xuchangCenter') }];
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: 'MLU', v: 'MLU' }];
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: 'RTX3080', v: 'RTX3080' }];
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') }];

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

@@ -82,7 +82,8 @@ const en = {
C2Net: 'C2Net',
OpenIOne: 'OpenI One',
OpenITwo: 'OpenI Two',
chenduCenter: 'ChenDu AI Center',
OpenIChengdu: 'OpenI ChengDu AI Chenter',
chengduCenter: 'ChengDu AI Center',
pclcci: 'PCL Cloud Computer Institute',
hefeiCenter: 'HeFei AI Center',
xuchangCenter: 'XuChang AI Center',


+ 2
- 1
web_src/vuepages/langs/config/zh-CN.js View File

@@ -82,7 +82,8 @@ const zh = {
C2Net: '智算集群',
OpenIOne: '云脑一',
OpenITwo: '云脑二',
chenduCenter: '成都人工智能计算中心',
OpenIChengdu: '启智成都智算',
chengduCenter: '成都智算',
pclcci: '鹏城云计算所',
hefeiCenter: '合肥类脑类脑智能开放平台',
xuchangCenter: '中原人工智能计算中心',


+ 3
- 2
web_src/vuepages/pages/resources/components/QueueDialog.vue View File

@@ -10,7 +10,8 @@
<span>{{ $t('resourcesManagement.resQueueName') }}</span>
</div>
<div class="content">
<el-input v-model="dataInfo.QueueCode" placeholder="" :disabled="type === 'edit'" maxlength="255"></el-input>
<el-input v-model="dataInfo.QueueCode" placeholder="" :disabled="type === 'edit'" maxlength="255">
</el-input>
</div>
</div>
<div class="form-row">
@@ -101,7 +102,7 @@ export default {
return {
dialogShow: false,
clusterList: [CLUSTERS[0]],
computingCenterList: [AI_CENTER[0], AI_CENTER[1]],
computingCenterList: [AI_CENTER[0], AI_CENTER[1], AI_CENTER[2]],
computingTypeList: [...COMPUTER_RESOURCES],
cardTypeList: [...ACC_CARD_TYPE],



+ 1
- 1
web_src/vuepages/pages/resources/components/SceneDialog.vue View File

@@ -88,7 +88,7 @@
<script>
import BaseDialog from '~/components/BaseDialog.vue';
import { getResQueueCode, getResSpecificationList, addResScene, updateResScene } from '~/apis/modules/resources';
import { JOB_TYPE, CLUSTERS, AI_CENTER, ACC_CARD_TYPE, SPECIFICATION_STATUS } from '~/const';
import { JOB_TYPE, CLUSTERS, ACC_CARD_TYPE, SPECIFICATION_STATUS } from '~/const';
import { getListValueWithKey } from '~/utils';

export default {


Loading…
Cancel
Save