Browse Source

Merge remote-tracking branch 'origin/V20220830' into res-manage

# Conflicts:
#	models/models.go
#	modules/cron/tasks_basic.go
tags/v1.22.8.2^2
chenyifan01 3 years ago
parent
commit
a692651642
91 changed files with 4192 additions and 1450 deletions
  1. +2
    -0
      go.sum
  2. +108
    -2
      models/cloudbrain.go
  3. +4
    -0
      models/cloudbrain_image.go
  4. +68
    -0
      models/cloudbrain_temp.go
  5. +28
    -13
      models/dataset.go
  6. +88
    -0
      models/dataset_reference.go
  7. +2
    -0
      models/models.go
  8. +0
    -1
      models/repo.go
  9. +1
    -1
      models/user.go
  10. +8
    -0
      modules/auth/dataset.go
  11. +2
    -1
      modules/auth/wechat/client.go
  12. +167
    -0
      modules/auth/wechat/cloudbrain.go
  13. +22
    -104
      modules/auth/wechat/template.go
  14. +5
    -5
      modules/cloudbrain/cloudbrain.go
  15. +31
    -25
      modules/cloudbrain/resty.go
  16. +43
    -0
      modules/context/permission_json.go
  17. +13
    -0
      modules/cron/tasks_basic.go
  18. +18
    -0
      modules/dataset/dataset.go
  19. +1
    -3
      modules/grampus/grampus.go
  20. +531
    -114
      modules/modelarts/modelarts.go
  21. +185
    -31
      modules/modelarts/resty.go
  22. +5
    -13
      modules/notification/wechat/wechat.go
  23. +2
    -0
      modules/setting/cloudbrain.go
  24. +5
    -2
      modules/setting/repository.go
  25. +14
    -0
      modules/setting/setting.go
  26. +0
    -41
      modules/storage/minio_ext.go
  27. +27
    -24
      modules/templates/helper.go
  28. +88
    -19
      options/locale/locale_en-US.ini
  29. +78
    -7
      options/locale/locale_zh-CN.ini
  30. +6
    -0
      routers/admin/cloudbrains.go
  31. +1
    -0
      routers/api/v1/api.go
  32. +119
    -4
      routers/api/v1/repo/cloudbrain.go
  33. +5
    -1
      routers/api/v1/repo/cloudbrain_dashboard.go
  34. +18
    -87
      routers/api/v1/repo/modelarts.go
  35. +7
    -15
      routers/home.go
  36. +65
    -55
      routers/repo/cloudbrain.go
  37. +115
    -11
      routers/repo/dataset.go
  38. +40
    -20
      routers/repo/grampus.go
  39. +227
    -220
      routers/repo/modelarts.go
  40. +12
    -1
      routers/repo/setting.go
  41. +12
    -2
      routers/routes/routes.go
  42. +16
    -17
      routers/search.go
  43. +6
    -0
      routers/user/home.go
  44. +19
    -0
      services/repository/dataset.go
  45. +7
    -3
      templates/admin/cloudbrain/list.tmpl
  46. +46
    -22
      templates/admin/cloudbrain/search.tmpl
  47. +46
    -22
      templates/admin/cloudbrain/search_dashboard.tmpl
  48. +10
    -10
      templates/custom/select_dataset_train.tmpl
  49. +2
    -2
      templates/custom/wait_count.tmpl
  50. +2
    -2
      templates/custom/wait_count_train.tmpl
  51. +9
    -8
      templates/home.tmpl
  52. +2
    -1
      templates/repo/attachment/upload.tmpl
  53. +12
    -10
      templates/repo/cloudbrain/benchmark/new.tmpl
  54. +22
    -8
      templates/repo/cloudbrain/inference/new.tmpl
  55. +19
    -15
      templates/repo/cloudbrain/inference/show.tmpl
  56. +5
    -1
      templates/repo/cloudbrain/new.tmpl
  57. +30
    -28
      templates/repo/cloudbrain/show.tmpl
  58. +20
    -9
      templates/repo/cloudbrain/trainjob/new.tmpl
  59. +96
    -37
      templates/repo/cloudbrain/trainjob/show.tmpl
  60. +83
    -61
      templates/repo/datasets/index.tmpl
  61. +8
    -0
      templates/repo/datasets/reference.tmpl
  62. +2
    -1
      templates/repo/debugjob/index.tmpl
  63. +17
    -7
      templates/repo/grampus/trainjob/gpu/new.tmpl
  64. +16
    -5
      templates/repo/grampus/trainjob/npu/new.tmpl
  65. +42
    -22
      templates/repo/grampus/trainjob/show.tmpl
  66. +1
    -1
      templates/repo/header.tmpl
  67. +22
    -7
      templates/repo/modelarts/inferencejob/new.tmpl
  68. +21
    -17
      templates/repo/modelarts/inferencejob/show.tmpl
  69. +3
    -5
      templates/repo/modelarts/notebook/new.tmpl
  70. +5
    -5
      templates/repo/modelarts/notebook/show.tmpl
  71. +6
    -4
      templates/repo/modelarts/trainjob/edit_para.tmpl
  72. +8
    -2
      templates/repo/modelarts/trainjob/index.tmpl
  73. +16
    -19
      templates/repo/modelarts/trainjob/new.tmpl
  74. +79
    -80
      templates/repo/modelarts/trainjob/show.tmpl
  75. +13
    -17
      templates/repo/modelarts/trainjob/version_new.tmpl
  76. +28
    -29
      templates/repo/modelmanage/convertIndex.tmpl
  77. +11
    -11
      templates/repo/modelmanage/convertshowinfo.tmpl
  78. +47
    -26
      templates/repo/modelmanage/index.tmpl
  79. +12
    -7
      templates/repo/modelmanage/showinfo.tmpl
  80. +4
    -0
      templates/user/dashboard/cloudbrains.tmpl
  81. +7
    -3
      web_src/js/components/MinioUploader.vue
  82. +20
    -14
      web_src/js/components/Model.vue
  83. +738
    -0
      web_src/js/components/dataset/referenceDataset.vue
  84. +87
    -35
      web_src/js/components/dataset/selectDataset.vue
  85. +17
    -10
      web_src/js/components/images/selectGrampusImages.vue
  86. +24
    -18
      web_src/js/components/images/selectImages.vue
  87. +48
    -4
      web_src/js/features/cloudbrainShow.js
  88. +45
    -20
      web_src/js/features/cloudrbanin.js
  89. +200
    -0
      web_src/js/features/i18nVue.js
  90. +19
    -2
      web_src/js/index.js
  91. +1
    -1
      web_src/less/_dashboard.less

+ 2
- 0
go.sum View File

@@ -713,12 +713,14 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1
github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/assertions v1.0.1 h1:voD4ITNjPL5jjBfgR/r8fPIIBrliWrWHeiJApdr3r4w=
github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
github.com/smartystreets/assertions v1.1.0 h1:MkTeG1DMwsrdH7QtLXy5W+fUxWq+vmb6cLmyJ7aRtF0=
github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM=
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8=
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=


+ 108
- 2
models/cloudbrain.go View File

@@ -153,7 +153,7 @@ type Cloudbrain struct {
VersionID int64 //版本id
VersionName string `xorm:"INDEX"` //当前版本
Uuid string //数据集id
DatasetName string
DatasetName string `xorm:"varchar(2000)"`
VersionCount int //任务的当前版本数量,不包括删除的
IsLatestVersion string //是否是最新版本,1是,0否
CommitID string //提交的仓库代码id
@@ -382,6 +382,9 @@ type CloudbrainsOptions struct {
ComputeResource string
BeginTimeUnix int64
EndTimeUnix int64
AiCenter string
NeedDeleteInfo string
Cluster string
}

type TaskPod struct {
@@ -1269,6 +1272,52 @@ type LogFile struct {
Name string
}

type JobList struct {
JobName string `json:"job_name"`
JobID int64 `json:"job_id"`
VersionID int64 `json:"version_id"`
VersionCount int64 `json:"version_count"`
Description string `json:"job_desc"`
IntStatus int `json:"status"`
}

type GetTrainJobListResult struct {
ErrorResult
JobTotalCount int `json:"job_total_count"` //查询到的用户创建作业总数
JobCountLimit int `json:"job_count_limit"` //用户还可以创建训练作业的数量
Quotas int `json:"quotas"` //训练作业的运行数量上限
JobList []JobList `json:"jobs"`
}

type JobVersionList struct {
VersionName string `json:"version_name"`
VersionID int64 `json:"version_id"`
IntStatus int `json:"status"`
}

type GetTrainJobVersionListResult struct {
ErrorResult
JobID int64 `json:"job_id"`
JobName string `json:"job_name"`
JobDesc string `json:"job_desc"`
VersionCount int64 `json:"version_count"`
JobVersionList []JobVersionList `json:"versions"`
}

type NotebookList struct {
JobName string `json:"name"`
JobID string `json:"id"`
Status string `json:"status"`
}

type GetNotebookListResult struct {
TotalCount int64 `json:"total"` //总的记录数量
CurrentPage int `json:"current"` //当前页数
TotalPages int `json:"pages"` //总的页数
Size int `json:"size"` //每一页的数量
NotebookList []NotebookList `json:"data"`
}

//Grampus
type GrampusResult struct {
ErrorCode int `json:"errorCode"`
@@ -1447,6 +1496,23 @@ func Cloudbrains(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, error) {
)
}
}
if (opts.AiCenter) != "" {
cond = cond.And(
builder.Like{"cloudbrain.ai_center", opts.AiCenter},
)
}
if (opts.Cluster) != "" {
if opts.Cluster == "resource_cluster_openi" {
cond = cond.And(
builder.Or(builder.Eq{"cloudbrain.type": TypeCloudBrainOne}, builder.Eq{"cloudbrain.type": TypeCloudBrainTwo}),
)
}
if opts.Cluster == "resource_cluster_c2net" {
cond = cond.And(
builder.Eq{"cloudbrain.type": TypeC2Net},
)
}
}

if (opts.IsLatestVersion) != "" {
cond = cond.And(builder.Or(builder.And(builder.Eq{"cloudbrain.is_latest_version": opts.IsLatestVersion}, builder.Eq{"cloudbrain.job_type": "TRAIN"}), builder.Neq{"cloudbrain.job_type": "TRAIN"}))
@@ -1746,6 +1812,12 @@ func GetCloudbrainsNeededStopByRepoID(repoID int64) ([]*Cloudbrain, error) {
return cloudBrains, err
}

func GetCloudbrainsNeededDeleteByRepoID(repoID int64) ([]*Cloudbrain, error) {
cloudBrains := make([]*Cloudbrain, 0)
err := x.Where("repo_id=?", repoID).Find(&cloudBrains)
return cloudBrains, err
}

func GetCloudbrainsByDisplayJobName(repoID int64, jobType string, displayJobName string) ([]*Cloudbrain, error) {
cloudBrains := make([]*Cloudbrain, 0)
err := x.Cols("job_id", "job_name", "repo_id", "user_id", "job_type", "display_job_name").Where("repo_id=? AND job_type =? AND lower(display_job_name) = lower(?)", repoID, jobType, displayJobName).Find(&cloudBrains)
@@ -1988,6 +2060,24 @@ func CloudbrainAll(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, error) {
}
}

if (opts.AiCenter) != "" {
cond = cond.And(
builder.Like{"cloudbrain.ai_center", opts.AiCenter},
)
}
if (opts.NeedDeleteInfo) != "" {
if opts.NeedDeleteInfo == "yes" {
cond = cond.And(
builder.And(builder.NotNull{"cloudbrain.deleted_at"}),
)
}
if opts.NeedDeleteInfo == "no" {
cond = cond.And(
builder.And(builder.IsNull{"cloudbrain.deleted_at"}),
)
}
}

if (opts.IsLatestVersion) != "" {
cond = cond.And(builder.Or(builder.And(builder.Eq{"cloudbrain.is_latest_version": opts.IsLatestVersion},
builder.Eq{"cloudbrain.job_type": "TRAIN"}), builder.Neq{"cloudbrain.job_type": "TRAIN"}))
@@ -2134,7 +2224,18 @@ func GetDatasetInfo(uuidStr string) (map[string]DatasetInfo, string, error) {
log.Error("GetAttachmentsByUUIDs failed: %v", err)
return nil, datasetNames, err
}
for i, attach := range attachs {
for i, tmpUuid := range uuids {
var attach *Attachment
for _, tmpAttach := range attachs {
if tmpAttach.UUID == tmpUuid {
attach = tmpAttach
break
}
}
if attach == nil {
log.Error("GetAttachmentsByUUIDs failed: %v", err)
return nil, datasetNames, err
}
fileName := strings.TrimSuffix(strings.TrimSuffix(strings.TrimSuffix(attach.Name, ".zip"), ".tar.gz"), ".tgz")
for _, datasetInfo := range datasetInfos {
if fileName == datasetInfo.Name {
@@ -2295,3 +2396,8 @@ func GetCloudbrainByIDs(ids []int64) ([]*Cloudbrain, error) {
In("id", ids).
Find(&cloudbrains)
}

func GetCloudbrainCountByJobName(jobName, jobType string, typeCloudbrain int) (int, error) {
count, err := x.Where("job_name = ? and job_type= ? and type = ?", jobName, jobType, typeCloudbrain).Count(new(Cloudbrain))
return int(count), err
}

+ 4
- 0
models/cloudbrain_image.go View File

@@ -518,6 +518,10 @@ func UpdateLocalImageStatus(image *Image) error {
return err
}

func UpdateAutoIncrementIndex() {
x.Exec("SELECT setval('image_id_seq', (SELECT MAX(id) from image))")
}

func DeleteLocalImage(id int64) error {
image := new(Image)
_, err := x.ID(id).Delete(image)


+ 68
- 0
models/cloudbrain_temp.go View File

@@ -0,0 +1,68 @@
package models

import (
"time"

"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
)

const (
TempJobId = "TEMP"
TempVersionId = TempJobId
TempJobStatus = TempJobId
)

type CloudbrainTemp struct {
ID int64 `xorm:"pk autoincr"`
JobID string `xorm:"NOT NULL DEFAULT 'TEMP'"`
VersionID string `xorm:"NOT NULL DEFAULT 'TEMP'"`
JobName string `xorm:"NOT NULL "`
Type int `xorm:"NOT NULL "`
JobType string `xorm:"INDEX NOT NULL DEFAULT 'DEBUG'"`
Status string `xorm:"INDEX NOT NULL DEFAULT 'TEMP'"`
QueryTimes int `xorm:"INDEX NOT NULL DEFAULT 0"`
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
DeletedAt time.Time `xorm:"deleted"`
}

func InsertCloudbrainTemp(temp *CloudbrainTemp) (err error) {
if _, err = x.Insert(temp); err != nil {
return err
}

return nil
}

func getCloudBrainTemp(temp *CloudbrainTemp) (*CloudbrainTemp, error) {
has, err := x.Get(temp)
if err != nil {
return nil, err
} else if !has {
return nil, ErrJobNotExist{}
}
return temp, nil
}

func GetCloudBrainTempJobs() ([]*CloudbrainTemp, error) {
jobs := make([]*CloudbrainTemp, 0, 10)
return jobs, x.In("status", TempJobStatus, string(ModelArtsStopping), string(ModelArtsTrainJobKilling)).
And("query_times < ?", setting.MaxTempQueryTimes).
Limit(100).
Find(&jobs)
}

func DeleteCloudbrainTemp(temp *CloudbrainTemp) error {
return deleteCloudbrainTemp(x, temp)
}

func deleteCloudbrainTemp(e Engine, temp *CloudbrainTemp) error {
_, err := e.ID(temp.ID).Delete(temp)
return err
}

func UpdateCloudbrainTemp(temp *CloudbrainTemp) error {
_, err := x.ID(temp.ID).AllCols().Update(temp)
return err
}

+ 28
- 13
models/dataset.go View File

@@ -6,6 +6,8 @@ import (
"sort"
"strings"

"code.gitea.io/gitea/modules/setting"

"code.gitea.io/gitea/modules/log"

"code.gitea.io/gitea/modules/timeutil"
@@ -88,7 +90,7 @@ func (datasets DatasetList) loadAttributes(e Engine) error {
if err := e.
Where("id > 0").
In("id", keysInt64(set)).
Cols("id", "owner_id", "owner_name", "lower_name", "name", "description", "alias", "lower_alias","is_private").
Cols("id", "owner_id", "owner_name", "lower_name", "name", "description", "alias", "lower_alias", "is_private").
Find(&repos); err != nil {
return fmt.Errorf("find repos: %v", err)
}
@@ -121,12 +123,12 @@ func (datasets DatasetList) loadAttachmentAttributes(opts *SearchDatasetOptions)
if attachment.DatasetID == datasets[i].ID {
if opts.StarByMe {

permission,ok := permissionMap[datasets[i].ID];
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.IsOrganization() {
if datasets[i].Repo.Owner.IsUserPartOfOrg(opts.User.ID) {
log.Info("user is member of org.")
permission = true
@@ -140,10 +142,10 @@ func (datasets DatasetList) loadAttachmentAttributes(opts *SearchDatasetOptions)
}
}

permissionMap[datasets[i].ID]=permission
permissionMap[datasets[i].ID] = permission
}

if permission{
if permission {
datasets[i].Attachments = append(datasets[i].Attachments, attachment)
} else if !attachment.IsPrivate {
datasets[i].Attachments = append(datasets[i].Attachments, attachment)
@@ -159,8 +161,8 @@ func (datasets DatasetList) loadAttachmentAttributes(opts *SearchDatasetOptions)
}

for i := range datasets {
if datasets[i].Attachments==nil{
datasets[i].Attachments=[]*Attachment{}
if datasets[i].Attachments == nil {
datasets[i].Attachments = []*Attachment{}
}
datasets[i].Repo.Owner = nil
}
@@ -178,7 +180,7 @@ type SearchDatasetOptions struct {
Category string
Task string
License string
DatasetIDs []int64 // 目前只在StarByMe为true时起作用
DatasetIDs []int64
ListOptions
SearchOrderBy
IsOwner bool
@@ -188,6 +190,7 @@ type SearchDatasetOptions struct {
JustNeedZipFile bool
NeedAttachment bool
UploadAttachmentByMe bool
QueryReference bool
}

func CreateDataset(dataset *Dataset) (err error) {
@@ -258,7 +261,7 @@ func SearchDatasetCondition(opts *SearchDatasetOptions) builder.Cond {
}
}
if len(opts.DatasetIDs) > 0 {
if opts.StarByMe {
if opts.StarByMe || (opts.RepoID == 0 && opts.QueryReference) {
cond = cond.And(builder.In("dataset.id", opts.DatasetIDs))
} else {
subCon := builder.NewCond()
@@ -329,13 +332,15 @@ func SearchDatasetByCondition(opts *SearchDatasetOptions, cond builder.Cond) (Da
return nil, 0, fmt.Errorf("Count: %v", err)
}

sess.Select(selectColumnsSql).Join("INNER", "repository", "repository.id = dataset.repo_id").
builderQuery := builder.Dialect(setting.Database.Type).Select("id", "title", "status", "category", "description", "download_times", "license", "task", "release_id", "user_id", "repo_id", "created_unix", "updated_unix", "num_stars", "recommend", "use_count").From(builder.Dialect(setting.Database.Type).Select(selectColumnsSql).From("dataset").Join("INNER", "repository", "repository.id = dataset.repo_id").
Join("INNER", "attachment", "attachment.dataset_id=dataset.id").
Where(cond).OrderBy(opts.SearchOrderBy.String())
Where(cond), "d").OrderBy(opts.SearchOrderBy.String())

if opts.PageSize > 0 {
sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize)
builderQuery.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize)
}
if err = sess.Find(&datasets); err != nil {

if err = sess.SQL(builderQuery).Find(&datasets); err != nil {
return nil, 0, fmt.Errorf("Dataset: %v", err)
}

@@ -585,3 +590,13 @@ func GetTeamDatasetIdsByUserID(userID int64) []int64 {
Cols("dataset.id").Find(&datasets)
return datasets
}

func UpdateDatasetCreateUser(ID int64, user *User) error {
_, err := x.Where("id = ?", ID).Cols("user_id").Update(&Dataset{
UserID: user.ID,
})
if err != nil {
return err
}
return nil
}

+ 88
- 0
models/dataset_reference.go View File

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

import (
"strconv"
"strings"

"code.gitea.io/gitea/modules/timeutil"
)

type DatasetReference struct {
ID int64 `xorm:"pk autoincr"`
RepoID int64 `xorm:"INDEX unique"`
DatasetID string `xorm:"TEXT"`
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
}

func GetDatasetIdsByRepoID(repoID int64) []int64 {
var datasets []int64
var datasetIds []string
_ = x.Table("dataset_reference").Where("repo_id=?", repoID).
Cols("dataset_reference.dataset_id").Find(&datasetIds)
if len(datasetIds) > 0 {
for _, datasetIdStr := range strings.Split(datasetIds[0], ",") {
datasetId, err := strconv.ParseInt(datasetIdStr, 10, 64)
if err != nil {
continue
}
datasets = append(datasets, datasetId)
}
}

return datasets
}

func HasReferenceDataset(repoID int64) bool {

var datasetIds []string
_ = x.Table("dataset_reference").Where("repo_id=?", repoID).
Cols("dataset_reference.dataset_id").Find(&datasetIds)
return len(datasetIds) > 0
}

func getReferenceDatasetStr(repoID int64) string {

var datasetIds []string
_ = x.Table("dataset_reference").Where("repo_id=?", repoID).
Cols("dataset_reference.dataset_id").Find(&datasetIds)
if len(datasetIds) > 0 {
return datasetIds[0]
}
return ""
}

func DeleteReferenceDatasetIdsByRepoID(repoID int64) error {

_, err := x.Exec("delete from dataset_reference where repo_id=?", repoID)
return err
}

func NewDatasetIdsByRepoID(repoID int64, datasetIds []int64) error {
if len(datasetIds) == 0 { //关联数据集数组为空
DeleteReferenceDatasetIdsByRepoID(repoID)
}
var datasetsStrArray []string
for _, datasetId := range datasetIds {
datasetsStrArray = append(datasetsStrArray, strconv.FormatInt(datasetId, 10))
}

newDatasetStr := strings.Join(datasetsStrArray, ",")
oldDatasetStr := getReferenceDatasetStr(repoID)
if newDatasetStr == oldDatasetStr { //关联数据集无变化,不需要处理
return nil
}
if oldDatasetStr != "" { //已经存在关联数据集
_, err := x.Exec("update dataset_reference set dataset_id=? where repo_id=?", newDatasetStr, repoID)

return err
} else {
datasetReference := DatasetReference{
DatasetID: newDatasetStr,
RepoID: repoID,
}

_, err := x.Insert(datasetReference)
return err
}

}

+ 2
- 0
models/models.go View File

@@ -150,6 +150,8 @@ func init() {
new(ResourceScene),
new(ResourceSceneSpec),
new(AdminOperateLog),
new(CloudbrainTemp),
new(DatasetReference),
)

tablesStatistic = append(tablesStatistic,


+ 0
- 1
models/repo.go View File

@@ -1788,7 +1788,6 @@ func DeleteRepository(doer *User, uid, repoID int64) error {

// Delete dataset attachment record and remove related files
deleteDatasetAttachmentByRepoId(sess, repoID)

if err = deleteBeans(sess,
&Access{RepoID: repo.ID},
&Action{RepoID: repo.ID},


+ 1
- 1
models/user.go View File

@@ -1784,7 +1784,7 @@ func SearchUsers(opts *SearchUserOptions) (users []*User, _ int64, _ error) {
orderby = SearchOrderByAlphabetically.String()
lowerKeyword := strings.ToLower(opts.Keyword)
if len(opts.Keyword) > 0 {
orderby = " CASE when lower_name='" + lowerKeyword + "' then 0 when strpos(lower_name,'" + lowerKeyword + "')>0 then 1 else 2 END ASC"
orderby = "CASE when lower_name='" + lowerKeyword + "' then 0 when strpos(lower_name,'" + lowerKeyword + "')>0 then 1 else 2 END ASC,lower_name ASC"
}
}
sess := x.Where(cond).OrderBy(orderby)


+ 8
- 0
modules/auth/dataset.go View File

@@ -44,3 +44,11 @@ type EditAttachmentForm struct {
func (f *EditAttachmentForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}

type ReferenceDatasetForm struct {
DatasetID []int64 `binding:"Required"`
}

func (f *ReferenceDatasetForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}

+ 2
- 1
modules/auth/wechat/client.go View File

@@ -61,11 +61,12 @@ type TemplateValue struct {
Color string `json:"color"`
}

type CloudbrainTaskData struct {
type DefaultWechatTemplate struct {
First TemplateValue `json:"first"`
Keyword1 TemplateValue `json:"keyword1"`
Keyword2 TemplateValue `json:"keyword2"`
Keyword3 TemplateValue `json:"keyword3"`
Keyword4 TemplateValue `json:"keyword4"`
Remark TemplateValue `json:"remark"`
}



+ 167
- 0
modules/auth/wechat/cloudbrain.go View File

@@ -0,0 +1,167 @@
package wechat

import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"fmt"
"time"
)

type JobOperateType string

const (
JobOperateTypeStart JobOperateType = "start"
JobOperateTypeStop JobOperateType = "stop"
)

type CloudbrainStartMsg struct {
}

func (CloudbrainStartMsg) Data(ctx *TemplateContext) *DefaultWechatTemplate {
return &DefaultWechatTemplate{
First: TemplateValue{Value: setting.CloudbrainStartedTitle},
Keyword1: TemplateValue{Value: ctx.Cloudbrain.DisplayJobName},
Keyword2: TemplateValue{Value: getJobTypeDisplayName(ctx.Cloudbrain.JobType)},
Keyword3: TemplateValue{Value: time.Unix(int64(ctx.Cloudbrain.CreatedUnix), 0).Format("2006-01-02 15:04:05")},
Remark: TemplateValue{Value: setting.CloudbrainStartedRemark},
}
}

func (CloudbrainStartMsg) ShouldSend(ctx *TemplateContext) bool {
if len(setting.CloudbrainStartedNotifyList) == 0 {
return false
}
for _, v := range setting.CloudbrainStartedNotifyList {
if v == ctx.Cloudbrain.JobType {
return true
}
}
return false
}

func (CloudbrainStartMsg) MsgId(ctx *TemplateContext) string {
return string(JobOperateTypeStart) + "_" + fmt.Sprint(ctx.Cloudbrain.ID)
}

func (CloudbrainStartMsg) Url(ctx *TemplateContext) string {
repo, err := models.GetRepositoryByID(ctx.Cloudbrain.RepoID)
if err != nil {
log.Error("CloudbrainStartMsg GetRepositoryByID error,%v", err)
return ""
}
return getCloudbrainTemplateUrl(*ctx.Cloudbrain, repo)
}

func (CloudbrainStartMsg) TemplateId(ctx *TemplateContext) string {
return setting.CloudbrainStartedTemplateId
}

type CloudbrainStopMsg struct {
}

func (CloudbrainStopMsg) Data(ctx *TemplateContext) *DefaultWechatTemplate {
return &DefaultWechatTemplate{
First: TemplateValue{Value: setting.CloudbrainStoppedTitle},
Keyword1: TemplateValue{Value: ctx.Cloudbrain.DisplayJobName},
Keyword2: TemplateValue{Value: getJobTypeDisplayName(ctx.Cloudbrain.JobType)},
Keyword3: TemplateValue{Value: time.Unix(int64(ctx.Cloudbrain.CreatedUnix), 0).Format("2006-01-02 15:04:05")},
Keyword4: TemplateValue{Value: time.Unix(int64(ctx.Cloudbrain.EndTime), 0).Format("2006-01-02 15:04:05")},
Remark: TemplateValue{Value: setting.CloudbrainStoppedRemark},
}
}

func (CloudbrainStopMsg) ShouldSend(ctx *TemplateContext) bool {
if len(setting.CloudbrainStoppedNotifyList) == 0 {
return false
}
for _, v := range setting.CloudbrainStoppedNotifyList {
if v == ctx.Cloudbrain.JobType {
if ctx.Cloudbrain.Duration > 0 && ctx.Cloudbrain.EndTime > 0 {
return true
}
break
}
}
return false
}

func (CloudbrainStopMsg) MsgId(ctx *TemplateContext) string {
return string(JobOperateTypeStop) + "_" + fmt.Sprint(ctx.Cloudbrain.ID)
}

func (CloudbrainStopMsg) Url(ctx *TemplateContext) string {
repo, err := models.GetRepositoryByID(ctx.Cloudbrain.RepoID)
if err != nil {
log.Error("CloudbrainStopMsg GetRepositoryByID error,%v", err)
return ""
}
return getCloudbrainTemplateUrl(*ctx.Cloudbrain, repo)
}

func (CloudbrainStopMsg) TemplateId(ctx *TemplateContext) string {
return setting.CloudbrainStoppedTemplateId
}

var startMsg = &CloudbrainStartMsg{}
var stopMsg = &CloudbrainStopMsg{}

func GetTemplateFromOperateType(operate JobOperateType) Template {
switch operate {
case JobOperateTypeStart:
return startMsg
case JobOperateTypeStop:
return stopMsg
}
return nil
}

func GetJobOperateTypeFromCloudbrainStatus(cloudbrain *models.Cloudbrain) JobOperateType {
if cloudbrain.IsTerminal() {
return JobOperateTypeStop
}
if cloudbrain.IsRunning() {
return JobOperateTypeStart
}
return ""
}

func getCloudbrainTemplateUrl(cloudbrain models.Cloudbrain, repo *models.Repository) string {
url := setting.AppURL + repo.FullName()

switch cloudbrain.JobType {
case string(models.JobTypeDebug):
if cloudbrain.ComputeResource == "CPU/GPU" {
url += "/cloudbrain/" + fmt.Sprint(cloudbrain.ID)
} else {
url += "/modelarts/notebook/" + fmt.Sprint(cloudbrain.ID)
}
case string(models.JobTypeBenchmark):
url += "/cloudbrain/benchmark/" + fmt.Sprint(cloudbrain.ID)
case string(models.JobTypeTrain):
if cloudbrain.Type == models.TypeCloudBrainOne {
url += "/cloudbrain/train-job/" + fmt.Sprint(cloudbrain.JobID)
} else if cloudbrain.Type == models.TypeCloudBrainTwo {
url += "/modelarts/train-job/" + fmt.Sprint(cloudbrain.JobID)
} else if cloudbrain.Type == models.TypeC2Net {
url += "/grampus/train-job/" + fmt.Sprint(cloudbrain.JobID)
}
case string(models.JobTypeInference):
url += "/modelarts/inference-job/" + fmt.Sprint(cloudbrain.JobID)
}
return url
}

func getJobTypeDisplayName(jobType string) string {
switch jobType {
case string(models.JobTypeDebug):
return "调试任务"
case string(models.JobTypeBenchmark):
return "评测任务"
case string(models.JobTypeTrain):
return "训练任务"
case string(models.JobTypeInference):
return "推理任务"
}
return ""
}

+ 22
- 104
modules/auth/wechat/template.go View File

@@ -3,143 +3,61 @@ package wechat
import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"errors"
"fmt"
"time"
)

type JobOperateType string

const (
JobOperateTypeStart JobOperateType = "start"
JobOperateTypeStop JobOperateType = "stop"
)
type Template interface {
ShouldSend(ctx *TemplateContext) bool
Data(ctx *TemplateContext) *DefaultWechatTemplate
MsgId(ctx *TemplateContext) string
Url(ctx *TemplateContext) string
TemplateId(ctx *TemplateContext) string
}

func GetJobOperateTypeFromCloudbrainStatus(cloudbrain *models.Cloudbrain) JobOperateType {
if cloudbrain.IsTerminal() {
return JobOperateTypeStop
}
if cloudbrain.IsRunning() {
return JobOperateTypeStart
}
return ""
type TemplateContext struct {
Cloudbrain *models.Cloudbrain
}

func SendCloudbrainStartedMsg(operateType JobOperateType, cloudbrain models.Cloudbrain) error {
func SendTemplateMsg(template Template, ctx *TemplateContext, userId int64) error {
defer func() {
if err := recover(); err != nil {
combinedErr := fmt.Errorf("%s\n%s", err, log.Stack(2))
log.Error("PANIC:", combinedErr)
}
}()
repo, err := models.GetRepositoryByID(cloudbrain.RepoID)
if err != nil {
log.Error("SendCloudbrainStartedMsg GetRepositoryByID error,%v", err)
}

if setting.CloudbrainStartedTemplateId == "" {
if !template.ShouldSend(ctx) {
log.Info("SendTemplateMsg should not Send.jobId=%d jobType=%s", ctx.Cloudbrain.ID, ctx.Cloudbrain.JobType)
return nil
}

openId := models.GetUserWechatOpenId(cloudbrain.UserID)
openId := models.GetUserWechatOpenId(userId)
if openId == "" {
log.Error("Wechat openId not exist,userId=%d", userId)
return errors.New("Wechat openId not exist")
}
data := CloudbrainTaskData{
First: TemplateValue{Value: getCloudbrainTemplateTitle(operateType)},
Keyword1: TemplateValue{Value: cloudbrain.DisplayJobName},
Keyword2: TemplateValue{Value: getJobTypeDisplayName(cloudbrain.JobType)},
Keyword3: TemplateValue{Value: time.Unix(int64(cloudbrain.CreatedUnix), 0).Format("2006-01-02 15:04:05")},
Remark: TemplateValue{Value: getCloudbrainTemplateRemark(operateType)},
}
req := TemplateMsgRequest{
ToUser: openId,
TemplateId: setting.CloudbrainStartedTemplateId,
Url: getCloudbrainTemplateUrl(cloudbrain, repo),
ClientMsgId: string(operateType) + "_" + fmt.Sprint(cloudbrain.ID),
Data: data,
TemplateId: template.TemplateId(ctx),
Url: template.Url(ctx),
ClientMsgId: template.MsgId(ctx),
Data: template.Data(ctx),
}
err, retryFlag := sendTemplateMsg(req)
if retryFlag {
log.Info("retrySendCloudbrainTemplateMsg calling")
log.Info("SendTemplateMsg calling")
refreshAccessToken()
err, _ = sendTemplateMsg(req)
if err != nil {
log.Error("SendCloudbrainStartedMsg err. %v", err)
log.Error("SendTemplateMsg err. %v", err)
return err
}
return nil
}
if err != nil {
log.Error("SendCloudbrainStartedMsg err. %v", err)
log.Error("SendTemplateMsg err. %v", err)
return err
}
log.Info("SendTemplateMsg success")
return nil
}

func getCloudbrainTemplateUrl(cloudbrain models.Cloudbrain, repo *models.Repository) string {
url := setting.AppURL + repo.FullName()

switch cloudbrain.JobType {
case string(models.JobTypeDebug):
if cloudbrain.ComputeResource == "CPU/GPU" {
url += "/cloudbrain/" + fmt.Sprint(cloudbrain.ID)
} else {
url += "/modelarts/notebook/" + fmt.Sprint(cloudbrain.ID)
}
case string(models.JobTypeBenchmark):
url += "/cloudbrain/benchmark/" + fmt.Sprint(cloudbrain.ID)
case string(models.JobTypeTrain):
if cloudbrain.Type == models.TypeCloudBrainOne {
url += "/cloudbrain/train-job/" + fmt.Sprint(cloudbrain.JobID)
} else if cloudbrain.Type == models.TypeCloudBrainTwo {
url += "/modelarts/train-job/" + fmt.Sprint(cloudbrain.JobID)
} else if cloudbrain.Type == models.TypeC2Net {
url += "/grampus/train-job/" + fmt.Sprint(cloudbrain.JobID)
}
case string(models.JobTypeInference):
url += "/modelarts/inference-job/" + fmt.Sprint(cloudbrain.JobID)
}
return url
}

func getCloudbrainTemplateTitle(operateType JobOperateType) string {
var title string
switch operateType {
case JobOperateTypeStart:
title = "您好,您提交的算力资源申请已通过,任务已启动,请您关注运行情况。"
case JobOperateTypeStop:
title = "您好,您提交的任务已运行结束。"
}

return title

}

func getCloudbrainTemplateRemark(operateType JobOperateType) string {
var remark string
switch operateType {
case JobOperateTypeStart:
remark = "感谢您的耐心等待。"
case JobOperateTypeStop:
remark = "点击可查看运行结果"
}

return remark

}

func getJobTypeDisplayName(jobType string) string {
switch jobType {
case string(models.JobTypeDebug):
return "调试任务"
case string(models.JobTypeBenchmark):
return "评测任务"
case string(models.JobTypeTrain):
return "训练任务"
case string(models.JobTypeInference):
return "推理任务"
}
return ""
}

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

@@ -82,7 +82,7 @@ type GenerateCloudBrainTaskReq struct {
}

func GetCloudbrainDebugCommand() string {
var command = `pip3 install jupyterlab==3 -i https://pypi.tuna.tsinghua.edu.cn/simple;service ssh stop;jupyter lab --ServerApp.shutdown_no_activity_timeout=` + setting.CullIdleTimeout + ` --TerminalManager.cull_inactive_timeout=` + setting.CullIdleTimeout + ` --TerminalManager.cull_interval=` + setting.CullInterval + ` --MappingKernelManager.cull_idle_timeout=` + setting.CullIdleTimeout + ` --MappingKernelManager.cull_interval=` + setting.CullInterval + ` --MappingKernelManager.cull_connected=True --MappingKernelManager.cull_busy=True --no-browser --ip=0.0.0.0 --allow-root --notebook-dir="/code" --port=80 --ServerApp.token="" --ServerApp.allow_origin="self https://cloudbrain.pcl.ac.cn" `
var command = `pip3 install jupyterlab==3 -i https://pypi.tuna.tsinghua.edu.cn/simple;pip3 install -U "nbclassic>=0.2.8" -i https://pypi.tuna.tsinghua.edu.cn/simple;service ssh stop;jupyter lab --ServerApp.shutdown_no_activity_timeout=` + setting.CullIdleTimeout + ` --TerminalManager.cull_inactive_timeout=` + setting.CullIdleTimeout + ` --TerminalManager.cull_interval=` + setting.CullInterval + ` --MappingKernelManager.cull_idle_timeout=` + setting.CullIdleTimeout + ` --MappingKernelManager.cull_interval=` + setting.CullInterval + ` --MappingKernelManager.cull_connected=True --MappingKernelManager.cull_busy=True --no-browser --ip=0.0.0.0 --allow-root --notebook-dir="/code" --port=80 --ServerApp.token="" --LabApp.token="" --ServerApp.allow_origin="self https://cloudbrain.pcl.ac.cn" `
return command
}

@@ -142,8 +142,8 @@ func isAdminOrImageCreater(ctx *context.Context, image *models.Image, err error)

func AdminOrOwnerOrJobCreaterRight(ctx *context.Context) {

var ID = ctx.Params(":id")
job, err := models.GetCloudbrainByID(ID)
var id = ctx.Params(":id")
job, err := models.GetCloudbrainByID(id)
if err != nil {
log.Error("GetCloudbrainByID failed:%v", err.Error())
ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
@@ -158,8 +158,8 @@ func AdminOrOwnerOrJobCreaterRight(ctx *context.Context) {

func AdminOrJobCreaterRight(ctx *context.Context) {

var ID = ctx.Params(":id")
job, err := models.GetCloudbrainByID(ID)
var id = ctx.Params(":id")
job, err := models.GetCloudbrainByID(id)
if err != nil {
log.Error("GetCloudbrainByID failed:%v", err.Error())
ctx.NotFound(ctx.Req.URL.RequestURI(), nil)


+ 31
- 25
modules/cloudbrain/resty.go View File

@@ -24,10 +24,11 @@ var (
)

const (
JobHasBeenStopped = "S410"
Public = "public"
Custom = "custom"
LogPageSize = 500
JobHasBeenStopped = "S410"
errInvalidToken = "S401"
Public = "public"
Custom = "custom"
LogPageSize = 500
LogPageTokenExpired = "5m"
pageSize = 15
QueuesDetailUrl = "/rest-server/api/v2/queuesdetail"
@@ -59,7 +60,7 @@ func loginCloudbrain() error {

res, err := client.R().
SetHeader("Content-Type", "application/json").
SetBody(map[string]interface{}{"username": username, "password": password, "expiration": "604800"}).
SetBody(map[string]interface{}{"username": username, "password": password, "expiration": conf.Expiration}).
SetResult(&loginResult).
Post(HOST + "/rest-server/api/v1/token")
if err != nil {
@@ -80,7 +81,8 @@ func GetQueuesDetail() (*map[string]int, error) {
var jobResult models.QueueDetailResult

var result = make(map[string]int, 0)

retry := 0
sendjob:
res, err := client.R().
SetHeader("Content-Type", "application/json").
SetAuthToken(TOKEN).
@@ -91,6 +93,12 @@ func GetQueuesDetail() (*map[string]int, error) {
return nil, fmt.Errorf("resty get queues detail failed: %s", err)
}

if jobResult.Code == errInvalidToken && retry < 1 {
retry++
_ = loginCloudbrain()
goto sendjob
}

if jobResult.Code != Success {
return nil, fmt.Errorf("jobResult err: %s", res.String())
}
@@ -122,16 +130,12 @@ sendjob:
Post(HOST + "/rest-server/api/v1/jobs/")

if err != nil {
if res != nil {
var response models.CloudBrainResult
json.Unmarshal(res.Body(), &response)
log.Error("code(%s), msg(%s)", response.Code, response.Msg)
return nil, fmt.Errorf(response.Msg)
}
return nil, fmt.Errorf("resty create job: %s", err)
}

if jobResult.Code == "S401" && retry < 1 {
var response models.CloudBrainResult
json.Unmarshal(res.Body(), &response)
if response.Code == errInvalidToken && retry < 1 {
retry++
_ = loginCloudbrain()
goto sendjob
@@ -163,7 +167,9 @@ sendjob:
return nil, fmt.Errorf("resty GetJob: %v", err)
}

if getJobResult.Code == "S401" && retry < 1 {
var response models.CloudBrainResult
json.Unmarshal(res.Body(), &response)
if response.Code == errInvalidToken && retry < 1 {
retry++
_ = loginCloudbrain()
goto sendjob
@@ -196,13 +202,8 @@ sendjob:
}

var response models.CloudBrainResult
err = json.Unmarshal(res.Body(), &response)
if err != nil {
log.Error("json.Unmarshal failed: %s", err.Error())
return &getImagesResult, fmt.Errorf("json.Unmarshal failed: %s", err.Error())
}

if response.Code == "S401" && retry < 1 {
json.Unmarshal(res.Body(), &response)
if response.Code == errInvalidToken && retry < 1 {
retry++
_ = loginCloudbrain()
goto sendjob
@@ -290,7 +291,9 @@ sendjob:
return fmt.Errorf("resty CommitImage: %v", err)
}

if result.Code == "S401" && retry < 1 {
var response models.CloudBrainResult
json.Unmarshal(res.Body(), &response)
if response.Code == errInvalidToken && retry < 1 {
retry++
_ = loginCloudbrain()
goto sendjob
@@ -312,6 +315,7 @@ sendjob:
}

err = models.WithTx(func(ctx models.DBContext) error {
models.UpdateAutoIncrementIndex()
if dbImage != nil {
dbImage.IsPrivate = params.IsPrivate
dbImage.Description = params.ImageDescription
@@ -441,7 +445,9 @@ sendjob:
return fmt.Errorf("resty StopJob: %v", err)
}

if result.Code == "S401" && retry < 1 {
var response models.CloudBrainResult
json.Unmarshal(res.Body(), &response)
if response.Code == errInvalidToken && retry < 1 {
retry++
_ = loginCloudbrain()
goto sendjob
@@ -497,7 +503,7 @@ func GetJobAllLog(scrollID string) (*models.GetJobLogResult, error) {
client := getRestyClient()
var result models.GetJobLogResult
req := models.GetAllJobLogParams{
Scroll: LogPageTokenExpired,
Scroll: LogPageTokenExpired,
ScrollID: scrollID,
}

@@ -521,7 +527,7 @@ func GetJobAllLog(scrollID string) (*models.GetJobLogResult, error) {
return &result, nil
}

func DeleteJobLogToken(scrollID string) (error) {
func DeleteJobLogToken(scrollID string) error {
checkSetting()
client := getRestyClient()
var result models.DeleteJobLogTokenResult


+ 43
- 0
modules/context/permission_json.go View File

@@ -0,0 +1,43 @@
package context

import (
"net/http"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/log"
"gitea.com/macaron/macaron"
)

func RequireRepoReaderJson(unitType models.UnitType) macaron.Handler {
return func(ctx *Context) {
if !ctx.Repo.CanRead(unitType) {
if log.IsTrace() {
if ctx.IsSigned {
log.Trace("Permission Denied: User %-v cannot read %-v in Repo %-v\n"+
"User in Repo has Permissions: %-+v",
ctx.User,
unitType,
ctx.Repo.Repository,
ctx.Repo.Permission)
} else {
log.Trace("Permission Denied: Anonymous user cannot read %-v in Repo %-v\n"+
"Anonymous user in Repo has Permissions: %-+v",
unitType,
ctx.Repo.Repository,
ctx.Repo.Permission)
}
}
ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("error.no_right")))
return
}
}
}

func RequireRepoWriterJson(unitType models.UnitType) macaron.Handler {
return func(ctx *Context) {
if !ctx.Repo.CanWrite(unitType) {
ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("error.no_right")))
return
}
}
}

+ 13
- 0
modules/cron/tasks_basic.go View File

@@ -6,6 +6,7 @@ package cron

import (
"code.gitea.io/gitea/services/cloudbrain/resource"
"code.gitea.io/gitea/modules/modelarts"
"context"
"time"

@@ -219,6 +220,17 @@ func registerSyncResourceSpecs() {
})
}

func registerSyncModelArtsTempJobs() {
RegisterTaskFatal("sync_model_arts_temp_jobs", &BaseConfig{
Enabled: true,
RunAtStart: false,
Schedule: "@every 1m",
}, func(ctx context.Context, _ *models.User, _ Config) error {
modelarts.SyncTempStatusJob()
return nil
})
}

func initBasicTasks() {
registerUpdateMirrorTask()
registerRepoHealthCheck()
@@ -240,4 +252,5 @@ func initBasicTasks() {
registerSyncCloudbrainStatus()
registerHandleOrgStatistic()
registerSyncResourceSpecs()
registerSyncModelArtsTempJobs()
}

+ 18
- 0
modules/dataset/dataset.go View File

@@ -1,5 +1,7 @@
package dataset

import "code.gitea.io/gitea/models"

func GetResourceType(cloudbrainType int) string {
if cloudbrainType == 0 {
return "CPU/GPU"
@@ -15,3 +17,19 @@ func GetStatusText(isPrivate bool) string {
return "dataset.public"
}
}

func IsShowDataSetOfCurrentRepo(repoID int64) bool {
repo := models.Repository{
ID: repoID,
}

dataset, _ := models.GetDatasetByRepo(&repo)
if dataset != nil {
return true
}
if models.HasReferenceDataset(repoID) {
return false
}
return true

}

+ 1
- 3
modules/grampus/grampus.go View File

@@ -23,9 +23,7 @@ const (
NpuWorkDir = "/cache/"

CommandPrepareScript = ";mkdir -p output;mkdir -p code;mkdir -p dataset;echo \"start loading script\";wget -q https://git.openi.org.cn/OpenIOSSG/script_for_grampus/archive/master.zip;" +
"echo \"finish loading script\";unzip -q master.zip;cd script_for_grampus;chmod 777 downloader_for_obs uploader_for_obs downloader_for_minio uploader_for_minio;"
//CommandPrepareScript = "pwd;cd /cache;mkdir -p output;mkdir -p code;mkdir -p dataset;echo \"start loading script\";wget -q https://git.openi.org.cn/OpenIOSSG/script_for_grampus/archive/master.zip;" +
// "echo \"finish loading script\";unzip -q master.zip;cd script_for_grampus;chmod 777 downloader_for_obs uploader_for_obs downloader_for_minio uploader_for_minio;"
"echo \"finish loading script\";unzip -q master.zip;cd script_for_grampus;chmod 777 downloader_for_obs uploader_for_npu downloader_for_minio uploader_for_gpu;"

CodeArchiveName = "master.zip"
)


+ 531
- 114
modules/modelarts/modelarts.go View File

@@ -6,8 +6,7 @@ import (
"fmt"
"path"
"strconv"

"code.gitea.io/gitea/modules/timeutil"
"strings"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
@@ -15,6 +14,7 @@ import (
"code.gitea.io/gitea/modules/notification"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/storage"
"code.gitea.io/gitea/modules/timeutil"
)

const (
@@ -59,7 +59,7 @@ const (
PerPage = 10
IsLatestVersion = "1"
NotLatestVersion = "0"
VersionCount = 1
VersionCountOne = 1

SortByCreateTime = "create_time"
ConfigTypeCustom = "custom"
@@ -134,6 +134,7 @@ type GenerateInferenceJobReq struct {
ModelVersion string
CkptName string
ResultUrl string
DatasetName string
}

type VersionInfo struct {
@@ -284,9 +285,24 @@ func GenerateNotebook2(ctx *context.Context, displayJobName, jobName, uuid, desc
})
if err != nil {
log.Error("createNotebook2 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.TypeCloudBrainTwo,
JobName: jobName,
JobType: string(models.JobTypeDebug),
})
if errTemp != nil {
log.Error("InsertCloudbrainTemp failed: %v", errTemp.Error())
return errTemp
}
}
return err
}
err = models.CreateCloudbrain(&models.Cloudbrain{
task := &models.Cloudbrain{
Status: jobResult.Status,
UserID: ctx.User.ID,
RepoID: ctx.Repo.Repository.ID,
@@ -302,16 +318,13 @@ func GenerateNotebook2(ctx *context.Context, displayJobName, jobName, uuid, desc
Description: description,
CreatedUnix: createTime,
UpdatedUnix: createTime,
})

if err != nil {
return err
}
task, err := models.GetCloudbrainByName(jobName)

err = models.CreateCloudbrain(task)
if err != nil {
log.Error("GetCloudbrainByName failed: %v", err.Error())
return err
}

stringId := strconv.FormatInt(task.ID, 10)
notification.NotifyOtherTask(ctx.User, ctx.Repo.Repository, stringId, displayJobName, models.ActionCreateDebugNPUTask)
return nil
@@ -364,7 +377,22 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error
})
}
if createErr != nil {
log.Error("CreateJob failed: %v", createErr.Error())
log.Error("createTrainJob failed: %v", createErr.Error())
if strings.HasPrefix(createErr.Error(), UnknownErrorPrefix) {
log.Info("(%s)unknown error, set temp status", req.DisplayJobName)
errTemp := models.InsertCloudbrainTemp(&models.CloudbrainTemp{
JobID: models.TempJobId,
VersionID: models.TempVersionId,
Status: models.TempJobStatus,
Type: models.TypeCloudBrainTwo,
JobName: req.JobName,
JobType: string(models.JobTypeTrain),
})
if errTemp != nil {
log.Error("InsertCloudbrainTemp failed: %v", errTemp.Error())
return errTemp
}
}
return createErr
}
jobId := strconv.FormatInt(jobResult.JobID, 10)
@@ -438,7 +466,7 @@ func GenerateTrainJobVersion(ctx *context.Context, req *GenerateTrainJobReq, job
createTime := timeutil.TimeStampNow()
var jobResult *models.CreateTrainJobResult
var createErr error
log.Info(" req.EngineID =" + fmt.Sprint(req.EngineID))
if req.EngineID < 0 {
jobResult, createErr = createTrainJobVersionUserImage(models.CreateTrainJobVersionUserImageParams{
Description: req.Description,
@@ -480,7 +508,22 @@ func GenerateTrainJobVersion(ctx *context.Context, req *GenerateTrainJobReq, job
}, jobId)
}
if createErr != nil {
log.Error("CreateJob failed: %v", createErr.Error())
log.Error("createTrainJobVersion failed: %v", createErr.Error())
if strings.HasPrefix(createErr.Error(), UnknownErrorPrefix) {
log.Info("(%s)unknown error, set temp status", req.DisplayJobName)
errTemp := models.InsertCloudbrainTemp(&models.CloudbrainTemp{
JobID: jobId,
VersionID: models.TempVersionId,
Status: models.TempJobStatus,
Type: models.TypeCloudBrainTwo,
JobName: req.JobName,
JobType: string(models.JobTypeTrain),
})
if errTemp != nil {
log.Error("InsertCloudbrainTemp failed: %v", errTemp.Error())
return errTemp
}
}
return createErr
}

@@ -540,7 +583,7 @@ func GenerateTrainJobVersion(ctx *context.Context, req *GenerateTrainJobReq, job
}

//将训练任务的上一版本的isLatestVersion设置为"0"
createErr = models.SetVersionCountAndLatestVersion(strconv.FormatInt(jobResult.JobID, 10), VersionTaskList[0].VersionName, VersionCount, NotLatestVersion, TotalVersionCount)
createErr = models.SetVersionCountAndLatestVersion(strconv.FormatInt(jobResult.JobID, 10), VersionTaskList[0].VersionName, VersionCountOne, NotLatestVersion, TotalVersionCount)
if createErr != nil {
ctx.ServerError("Update IsLatestVersion failed", createErr)
return createErr
@@ -549,99 +592,6 @@ func GenerateTrainJobVersion(ctx *context.Context, req *GenerateTrainJobReq, job
return createErr
}

func GenerateTrainJobVersionByUserImage(ctx *context.Context, req *GenerateTrainJobReq, jobId string) (err error) {
createTime := timeutil.TimeStampNow()
jobResult, err := createTrainJobUserImage(models.CreateUserImageTrainJobParams{
JobName: req.JobName,
Description: req.Description,
Config: models.UserImageConfig{
WorkServerNum: req.WorkServerNumber,
AppUrl: req.CodeObsPath,
BootFileUrl: req.BootFileUrl,
DataUrl: req.DataUrl,
TrainUrl: req.TrainUrl,
LogUrl: req.LogUrl,
PoolID: req.PoolID,
CreateVersion: true,
Flavor: models.Flavor{
Code: req.FlavorCode,
},
Parameter: req.Parameters,
UserImageUrl: req.UserImageUrl,
UserCommand: req.UserCommand,
},
})
if err != nil {
log.Error("CreateJob failed: %v", err.Error())
return err
}

var jobTypes []string
jobTypes = append(jobTypes, string(models.JobTypeTrain))
repo := ctx.Repo.Repository
VersionTaskList, VersionListCount, err := models.CloudbrainsVersionList(&models.CloudbrainsOptions{
RepoID: repo.ID,
Type: models.TypeCloudBrainTwo,
JobTypes: jobTypes,
JobID: strconv.FormatInt(jobResult.JobID, 10),
})
if err != nil {
ctx.ServerError("Cloudbrain", err)
return err
}
//将当前版本的isLatestVersion设置为"1"和任务数量更新,任务数量包括当前版本数VersionCount和历史创建的总版本数TotalVersionCount

err = models.CreateCloudbrain(&models.Cloudbrain{
Status: TransTrainJobStatus(jobResult.Status),
UserID: ctx.User.ID,
RepoID: ctx.Repo.Repository.ID,
JobID: strconv.FormatInt(jobResult.JobID, 10),
JobName: req.JobName,
DisplayJobName: req.DisplayJobName,
JobType: string(models.JobTypeTrain),
Type: models.TypeCloudBrainTwo,
VersionID: jobResult.VersionID,
VersionName: jobResult.VersionName,
Uuid: req.Uuid,
DatasetName: req.DatasetName,
CommitID: req.CommitID,
IsLatestVersion: req.IsLatestVersion,
PreVersionName: req.PreVersionName,
ComputeResource: models.NPUResource,
EngineID: MORDELART_USER_IMAGE_ENGINE_ID,
Image: req.UserImageUrl,
TrainUrl: req.TrainUrl,
BranchName: req.BranchName,
Parameters: req.Params,
BootFile: req.BootFile,
DataUrl: req.DataUrl,
LogUrl: req.LogUrl,
PreVersionId: req.PreVersionId,
FlavorCode: req.FlavorCode,
Description: req.Description,
WorkServerNumber: req.WorkServerNumber,
FlavorName: req.FlavorName,
EngineName: req.EngineName,
TotalVersionCount: VersionTaskList[0].TotalVersionCount + 1,
VersionCount: VersionListCount + 1,
CreatedUnix: createTime,
UpdatedUnix: createTime,
})
if err != nil {
log.Error("CreateCloudbrain(%s) failed:%v", req.JobName, err.Error())
return err
}

//将训练任务的上一版本的isLatestVersion设置为"0"
err = models.SetVersionCountAndLatestVersion(strconv.FormatInt(jobResult.JobID, 10), VersionTaskList[0].VersionName, VersionCount, NotLatestVersion, TotalVersionCount)
if err != nil {
ctx.ServerError("Update IsLatestVersion failed", err)
return err
}

return err
}

func TransTrainJobStatus(status int) string {
switch status {
case 0:
@@ -722,15 +672,30 @@ func GenerateInferenceJob(ctx *context.Context, req *GenerateInferenceJobReq) (e
},
})
if err != nil {
log.Error("CreateJob failed: %v", err.Error())
log.Error("createInferenceJob failed: %v", err.Error())
if strings.HasPrefix(err.Error(), UnknownErrorPrefix) {
log.Info("(%s)unknown error, set temp status", req.DisplayJobName)
err = models.InsertCloudbrainTemp(&models.CloudbrainTemp{
JobID: models.TempJobId,
VersionID: models.TempVersionId,
Status: models.TempJobStatus,
Type: models.TypeCloudBrainTwo,
JobName: req.JobName,
JobType: string(models.JobTypeInference),
})
if err != nil {
log.Error("InsertCloudbrainTemp failed: %v", err.Error())
return err
}
}
return err
}

attach, err := models.GetAttachmentByUUID(req.Uuid)
if err != nil {
log.Error("GetAttachmentByUUID(%s) failed:%v", strconv.FormatInt(jobResult.JobID, 10), err.Error())
return err
}
// attach, err := models.GetAttachmentByUUID(req.Uuid)
// if err != nil {
// log.Error("GetAttachmentByUUID(%s) failed:%v", strconv.FormatInt(jobResult.JobID, 10), err.Error())
// return err
// }
jobID := strconv.FormatInt(jobResult.JobID, 10)
err = models.CreateCloudbrain(&models.Cloudbrain{
Status: TransTrainJobStatus(jobResult.Status),
@@ -744,7 +709,7 @@ func GenerateInferenceJob(ctx *context.Context, req *GenerateInferenceJobReq) (e
VersionID: jobResult.VersionID,
VersionName: jobResult.VersionName,
Uuid: req.Uuid,
DatasetName: attach.Name,
DatasetName: req.DatasetName,
CommitID: req.CommitID,
EngineID: req.EngineID,
TrainUrl: req.TrainUrl,
@@ -807,3 +772,455 @@ func InitSpecialPool() {
json.Unmarshal([]byte(setting.ModelArtsSpecialPools), &SpecialPools)
}
}

func HandleTrainJobInfo(task *models.Cloudbrain) error {

result, err := GetTrainJob(task.JobID, strconv.FormatInt(task.VersionID, 10))
if err != nil {
log.Error("GetTrainJob(%s) failed:%v", task.DisplayJobName, err)
return err
}

if result != nil {
oldStatus := task.Status
task.Status = TransTrainJobStatus(result.IntStatus)
task.Duration = result.Duration / 1000
task.TrainJobDuration = result.TrainJobDuration

if task.StartTime == 0 && result.StartTime > 0 {
task.StartTime = timeutil.TimeStamp(result.StartTime / 1000)
}
task.TrainJobDuration = models.ConvertDurationToStr(task.Duration)
if task.EndTime == 0 && models.IsTrainJobTerminal(task.Status) && task.StartTime > 0 {
task.EndTime = task.StartTime.Add(task.Duration)
}
task.CorrectCreateUnix()
if oldStatus != task.Status {
notification.NotifyChangeCloudbrainStatus(task, oldStatus)
}
err = models.UpdateJob(task)
if err != nil {
log.Error("UpdateJob(%s) failed:%v", task.JobName, err)
return err
}
}

return nil
}

func HandleNotebookInfo(task *models.Cloudbrain) error {

result, err := GetNotebook2(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
}

func SyncTempStatusJob() {
jobs, err := models.GetCloudBrainTempJobs()
if err != nil {
log.Error("GetCloudBrainTempJobs failed:%v", err.Error())
return
}

for _, temp := range jobs {
log.Info("start to handle record: %s", temp.JobName)
if temp.Type == models.TypeCloudBrainTwo {
if temp.JobType == string(models.JobTypeDebug) {
err = handleNotebook(temp)
if err != nil {
log.Error("handleNotebook falied:%v", err)
break
}
} else if temp.JobType == string(models.JobTypeTrain) || temp.JobType == string(models.JobTypeInference) {
_, err = models.GetCloudbrainByJobID(temp.JobID)
if err != nil {
//one version
err = handleTrainJob(temp)
if err != nil {
log.Error("handleTrainJob falied:%v", err)
break
}
} else {
//multi version
err = handleTrainJobMultiVersion(temp)
if err != nil {
log.Error("handleTrainJobMultiVersion falied:%v", err)
break
}
}
}
}
}

return
}

func handleNotebook(temp *models.CloudbrainTemp) error {
if temp.Status == models.TempJobStatus {
err := handleTempNotebook(temp)
if err != nil {
log.Error("handleTempNotebook failed:%v", err)
return err
}
} else if temp.Status == string(models.ModelArtsStopping) {
res, err := GetNotebook2(temp.JobID)
if err != nil {
log.Error("GetNotebook2 failed:%v", err)
return err
}

temp.Status = res.Status
if temp.Status == string(models.ModelArtsStopped) {
err = models.UpdateCloudbrainTemp(temp)
if err != nil {
log.Error("UpdateCloudbrainTemp failed:%v", err)
return err
}

_, err := DelNotebook2(temp.JobID)
if err != nil {
log.Error("DelNotebook2 failed:%v", err)
return err
}

temp.Status = string(models.ModelArtsDeleted)
err = models.UpdateCloudbrainTemp(temp)
if err != nil {
log.Error("UpdateCloudbrainTemp failed:%v", err)
return err
}
}
}

return nil
}

func handleTempNotebook(temp *models.CloudbrainTemp) error {
var err error
var isExist bool

for {
result, err := GetNotebookList(1000, 0, "createTime", "DESC", temp.JobName)
if err != nil {
log.Error("GetNotebookList failed:%v", err)
break
}

temp.QueryTimes++
err = models.UpdateCloudbrainTemp(temp)
if err != nil {
log.Error("UpdateCloudbrainTemp failed:%v", err)
}

if result != nil {
for _, notebook := range result.NotebookList {
if temp.JobID == models.TempJobId {
//new notebook
if notebook.JobName == temp.JobName {
isExist = true
temp.Status = notebook.Status
temp.JobID = notebook.JobID
break
}
} else {
//restart: always can find one record
if notebook.JobName == temp.JobName {
if notebook.Status != string(models.ModelArtsStopped) {
isExist = true
temp.Status = notebook.Status
temp.JobID = notebook.JobID
break
}
}
}
}

if isExist {
log.Info("find the record(%s), status(%s)", temp.JobName, temp.Status)
if temp.Status == string(models.ModelArtsCreateFailed) {
err = models.UpdateCloudbrainTemp(temp)
if err != nil {
log.Error("UpdateCloudbrainTemp failed:%v", err)
break
}

_, err := DelNotebook2(temp.JobID)
if err != nil {
log.Error("DelNotebook2(%s) failed:%v", temp.JobName, err)
break
}

temp.Status = string(models.ModelArtsDeleted)
} else {
_, err := ManageNotebook2(temp.JobID, models.NotebookAction{Action: models.ActionStop})
if err != nil {
log.Error("ManageNotebook2(%s) failed:%v", temp.JobName, err)
break
}
temp.Status = string(models.ModelArtsStopping)
}

models.UpdateCloudbrainTemp(temp)
} else {
log.Error("can not find the record(%s) till now", temp.JobName)
err = errors.New("not found")
break
}
} else {
log.Error("can not find the record(%s) till now", temp.JobName)
err = errors.New("not found")
break
}

break
}

if temp.QueryTimes >= setting.MaxTempQueryTimes && !isExist {
log.Info("reach MaxTempQueryTimes, set the job failed")

temp.Status = string(models.ModelArtsTrainJobFailed)
err = models.UpdateCloudbrainTemp(temp)
if err != nil {
log.Error("UpdateCloudbrainTemp(%s) failed:%v", temp.JobName, err)
return err
}
}

return err
}

func handleTrainJob(temp *models.CloudbrainTemp) error {
if temp.Status == models.TempJobStatus {
err := handleTempTrainJob(temp)
if err != nil {
log.Error("handleTempTrainJob failed:%v", err)
return err
}
} else if temp.Status == string(models.ModelArtsTrainJobKilling) {
res, err := GetTrainJob(temp.JobID, temp.VersionID)
if err != nil {
log.Error("GetTrainJob failed:%v", err)
return err
}

temp.Status = TransTrainJobStatus(res.IntStatus)
if temp.Status == string(models.ModelArtsTrainJobKilled) {
err = models.UpdateCloudbrainTemp(temp)
if err != nil {
log.Error("UpdateCloudbrainTemp failed:%v", err)
return err
}

_, err := DelTrainJob(temp.JobID)
if err != nil {
log.Error("DelTrainJob failed:%v", err)
return err
}

temp.Status = string(models.ModelArtsDeleted)
err = models.UpdateCloudbrainTemp(temp)
if err != nil {
log.Error("UpdateCloudbrainTemp failed:%v", err)
return err
}
}
}

return nil
}

func handleTrainJobMultiVersion(temp *models.CloudbrainTemp) error {
if temp.Status == models.TempJobStatus {
err := handleTempTrainJobMultiVersion(temp)
if err != nil {
log.Error("handleTempTrainJobMultiVersion failed:%v", err)
return err
}
} else if temp.Status == string(models.ModelArtsTrainJobKilling) {
res, err := GetTrainJob(temp.JobID, temp.VersionID)
if err != nil {
log.Error("GetTrainJob failed:%v", err)
return err
}

temp.Status = TransTrainJobStatus(res.IntStatus)
if temp.Status == string(models.ModelArtsTrainJobKilled) {
err = models.UpdateCloudbrainTemp(temp)
if err != nil {
log.Error("UpdateCloudbrainTemp failed:%v", err)
return err
}

_, err := DelTrainJobVersion(temp.JobID, temp.VersionID)
if err != nil {
log.Error("DelTrainJob failed:%v", err)
return err
}

temp.Status = string(models.ModelArtsDeleted)
err = models.UpdateCloudbrainTemp(temp)
if err != nil {
log.Error("UpdateCloudbrainTemp failed:%v", err)
return err
}
}

}

return nil
}

func handleTempTrainJobMultiVersion(temp *models.CloudbrainTemp) error {
var err error
var isExist bool

for {
result, err := GetTrainJobVersionList(1000, 1, temp.JobID)
if err != nil {
log.Error("GetTrainJobVersionList failed:%v", err)
break
}

temp.QueryTimes++
err = models.UpdateCloudbrainTemp(temp)
if err != nil {
log.Error("UpdateCloudbrainTemp failed:%v", err)
}

if result != nil {
count, _ := models.GetCloudbrainCountByJobName(temp.JobName, temp.JobType, temp.Type)
if result.VersionCount == int64(count+1) {
isExist = true
temp.Status = TransTrainJobStatus(result.JobVersionList[0].IntStatus)
temp.VersionID = strconv.FormatInt(result.JobVersionList[0].VersionID, 10)

log.Info("find the record(%s), status(%s)", temp.JobName, temp.Status)

_, err := StopTrainJob(temp.JobID, temp.VersionID)
if err != nil {
log.Error("StopTrainJob failed:%v", err)
break
}
temp.Status = string(models.ModelArtsTrainJobKilling)
err = models.UpdateCloudbrainTemp(temp)
if err != nil {
log.Error("UpdateCloudbrainTemp(%s) failed:%v", temp.JobName, err)
break
}
} else {
log.Error("can not find the record(%s) till now", temp.JobName)
err = errors.New("not found")
break
}
}

break
}

if temp.QueryTimes >= setting.MaxTempQueryTimes && !isExist {
log.Info("reach MaxTempQueryTimes, set the job failed")

temp.Status = string(models.ModelArtsTrainJobFailed)
err = models.UpdateCloudbrainTemp(temp)
if err != nil {
log.Error("UpdateCloudbrainTemp(%s) failed:%v", temp.JobName, err)
return err
}
}

return err
}

func handleTempTrainJob(temp *models.CloudbrainTemp) error {
var err error
var isExist bool

for {
result, err := GetTrainJobList(1000, 1, "create_time", "desc", temp.JobName)
if err != nil {
log.Error("GetTrainJobList failed:%v", err)
break
}

temp.QueryTimes++
err = models.UpdateCloudbrainTemp(temp)
if err != nil {
log.Error("UpdateCloudbrainTemp failed:%v", err)
}

if result != nil {
for _, job := range result.JobList {
if temp.JobName == job.JobName && TransTrainJobStatus(job.IntStatus) != string(models.ModelArtsTrainJobFailed) {
isExist = true
temp.Status = TransTrainJobStatus(job.IntStatus)
temp.JobID = strconv.FormatInt(job.JobID, 10)
temp.VersionID = strconv.FormatInt(job.VersionID, 10)

log.Info("find the record(%s), status(%s)", temp.JobName, temp.Status)

_, err = StopTrainJob(temp.JobID, temp.VersionID)
if err != nil {
log.Error("StopTrainJob(%s) failed:%v", temp.JobName, err)
break
}

temp.Status = string(models.ModelArtsTrainJobKilling)
err = models.UpdateCloudbrainTemp(temp)
if err != nil {
log.Error("UpdateCloudbrainTemp(%s) failed:%v", temp.JobName, err)
break
}
}
}

if !isExist {
log.Error("can not find the record(%s) till now", temp.JobName)
err = errors.New("not found")
break
}
}

break
}

if temp.QueryTimes >= setting.MaxTempQueryTimes && !isExist {
log.Info("reach MaxTempQueryTimes, set the job failed")

temp.Status = string(models.ModelArtsTrainJobFailed)
err = models.UpdateCloudbrainTemp(temp)
if err != nil {
log.Error("UpdateCloudbrainTemp(%s) failed:%v", temp.JobName, err)
return err
}
}

return err
}

+ 185
- 31
modules/modelarts/resty.go View File

@@ -37,6 +37,7 @@ const (
NotebookNotFound = "ModelArts.6404"
NotebookNoPermission = "ModelArts.6407"
NotebookInvalid = "ModelArts.6400"
UnknownErrorPrefix = "UNKNOWN:"
)

func getRestyClient() *resty.Client {
@@ -298,6 +299,10 @@ sendjob:
return &result, fmt.Errorf("son.Unmarshal failed: %s", err.Error())
}

if res.StatusCode() == http.StatusBadGateway {
return &result, fmt.Errorf(UnknownErrorPrefix+"createNotebook2 failed(%s): %s", response.ErrorCode, response.ErrorMsg)
}

if len(response.ErrorCode) != 0 {
log.Error("ManageNotebook2 failed(%s): %s", response.ErrorCode, response.ErrorMsg)
if response.ErrorCode == modelartsIllegalToken && retry < 1 {
@@ -506,23 +511,27 @@ sendjob:
log.Error("json.Unmarshal failed(%s): %v", res.String(), err.Error())
return &result, fmt.Errorf("json.Unmarshal failed(%s): %v", res.String(), err.Error())
}
log.Error("createTrainJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
BootFileErrorMsg := "Invalid OBS path '" + createJobParams.Config.BootFileUrl + "'."
DataSetErrorMsg := "Invalid OBS path '" + createJobParams.Config.DataUrl + "'."
if temp.ErrorMsg == BootFileErrorMsg {
log.Error("启动文件错误!createTrainJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
log.Error("createTrainJobUserImage failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
bootFileErrorMsg := "Invalid OBS path '" + createJobParams.Config.BootFileUrl + "'."
dataSetErrorMsg := "Invalid OBS path '" + createJobParams.Config.DataUrl + "'."
if temp.ErrorMsg == bootFileErrorMsg {
log.Error("启动文件错误!createTrainJobUserImage failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
return &result, fmt.Errorf("启动文件错误!")
}
if temp.ErrorMsg == DataSetErrorMsg {
log.Error("数据集错误!createTrainJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
if temp.ErrorMsg == dataSetErrorMsg {
log.Error("数据集错误!createTrainJobUserImage failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
return &result, fmt.Errorf("数据集错误!")
}
return &result, fmt.Errorf("createTrainJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
if res.StatusCode() == http.StatusBadGateway {
return &result, fmt.Errorf(UnknownErrorPrefix+"createTrainJobUserImage failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
} else {
return &result, fmt.Errorf("createTrainJobUserImage failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
}
}

if !result.IsSuccess {
log.Error("createTrainJob failed(%s): %s", result.ErrorCode, result.ErrorMsg)
return &result, fmt.Errorf("createTrainJob failed(%s): %s", result.ErrorCode, result.ErrorMsg)
log.Error("createTrainJobUserImage failed(%s): %s", result.ErrorCode, result.ErrorMsg)
return &result, fmt.Errorf("createTrainJobUserImage failed(%s): %s", result.ErrorCode, result.ErrorMsg)
}

return &result, nil
@@ -547,9 +556,6 @@ sendjob:
return nil, fmt.Errorf("resty create train-job: %s", err)
}

req, _ := json.Marshal(createJobParams)
log.Info("%s", req)

if res.StatusCode() == http.StatusUnauthorized && retry < 1 {
retry++
_ = getToken()
@@ -563,17 +569,21 @@ sendjob:
return &result, fmt.Errorf("json.Unmarshal failed(%s): %v", res.String(), err.Error())
}
log.Error("createTrainJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
BootFileErrorMsg := "Invalid OBS path '" + createJobParams.Config.BootFileUrl + "'."
DataSetErrorMsg := "Invalid OBS path '" + createJobParams.Config.DataUrl + "'."
if temp.ErrorMsg == BootFileErrorMsg {
bootFileErrorMsg := "Invalid OBS path '" + createJobParams.Config.BootFileUrl + "'."
dataSetErrorMsg := "Invalid OBS path '" + createJobParams.Config.DataUrl + "'."
if temp.ErrorMsg == bootFileErrorMsg {
log.Error("启动文件错误!createTrainJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
return &result, fmt.Errorf("启动文件错误!")
}
if temp.ErrorMsg == DataSetErrorMsg {
if temp.ErrorMsg == dataSetErrorMsg {
log.Error("数据集错误!createTrainJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
return &result, fmt.Errorf("数据集错误!")
}
return &result, fmt.Errorf("createTrainJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
if res.StatusCode() == http.StatusBadGateway {
return &result, fmt.Errorf(UnknownErrorPrefix+"createTrainJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
} else {
return &result, fmt.Errorf("createTrainJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
}
}

if !result.IsSuccess {
@@ -603,9 +613,6 @@ sendjob:
return nil, fmt.Errorf("resty create train-job version: %s", err)
}

req, _ := json.Marshal(createJobVersionParams)
log.Info("%s", req)

if res.StatusCode() == http.StatusUnauthorized && retry < 1 {
retry++
_ = getToken()
@@ -618,17 +625,23 @@ sendjob:
log.Error("json.Unmarshal failed(%s): %v", res.String(), err.Error())
return &result, fmt.Errorf("json.Unmarshal failed(%s): %v", res.String(), err.Error())
}
BootFileErrorMsg := "Invalid OBS path '" + createJobVersionParams.Config.BootFileUrl + "'."
DataSetErrorMsg := "Invalid OBS path '" + createJobVersionParams.Config.DataUrl + "'."
if temp.ErrorMsg == BootFileErrorMsg {

log.Error("createTrainJobVersion failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
bootFileErrorMsg := "Invalid OBS path '" + createJobVersionParams.Config.BootFileUrl + "'."
dataSetErrorMsg := "Invalid OBS path '" + createJobVersionParams.Config.DataUrl + "'."
if temp.ErrorMsg == bootFileErrorMsg {
log.Error("启动文件错误!createTrainJobVersion failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
return &result, fmt.Errorf("启动文件错误!")
}
if temp.ErrorMsg == DataSetErrorMsg {
if temp.ErrorMsg == dataSetErrorMsg {
log.Error("数据集错误!createTrainJobVersion failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
return &result, fmt.Errorf("数据集错误!")
}
return &result, fmt.Errorf("createTrainJobVersion failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
if res.StatusCode() == http.StatusBadGateway {
return &result, fmt.Errorf(UnknownErrorPrefix+"createTrainJobVersion failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
} else {
return &result, fmt.Errorf("createTrainJobVersion failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
}
}

if !result.IsSuccess {
@@ -761,9 +774,6 @@ sendjob:
goto sendjob
}

//temp, _ := json.Marshal(req)
//log.Info("%s", temp)

if res.StatusCode() != http.StatusOK {
var temp models.ErrorResult
if err = json.Unmarshal([]byte(res.String()), &temp); err != nil {
@@ -1172,7 +1182,11 @@ sendjob:
log.Error("数据集错误!createInferenceJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
return &result, fmt.Errorf("数据集错误!")
}
return &result, fmt.Errorf("createInferenceJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
if res.StatusCode() == http.StatusBadGateway {
return &result, fmt.Errorf(UnknownErrorPrefix+"createInferenceJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
} else {
return &result, fmt.Errorf("createInferenceJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
}
}

if !result.IsSuccess {
@@ -1212,7 +1226,11 @@ sendjob:
err = json.Unmarshal(res.Body(), &response)
if err != nil {
log.Error("json.Unmarshal failed: %s", err.Error())
return &result, fmt.Errorf("son.Unmarshal failed: %s", err.Error())
return &result, fmt.Errorf("json.Unmarshal failed: %s", err.Error())
}

if res.StatusCode() == http.StatusBadGateway {
return &result, fmt.Errorf(UnknownErrorPrefix+"createNotebook2 failed(%s): %s", response.ErrorCode, response.ErrorMsg)
}

if len(response.ErrorCode) != 0 {
@@ -1271,3 +1289,139 @@ sendjob:

return &result, nil
}

func GetTrainJobList(perPage, page int, sortBy, order, searchContent string) (*models.GetTrainJobListResult, error) {
checkSetting()
client := getRestyClient()
var result models.GetTrainJobListResult

retry := 0

sendjob:
res, err := client.R().
SetQueryParams(map[string]string{
"per_page": strconv.Itoa(perPage),
"page": strconv.Itoa(page),
"sortBy": sortBy,
"order": order,
"search_content": searchContent,
}).
SetAuthToken(TOKEN).
SetResult(&result).
Get(HOST + "/v1/" + setting.ProjectID + urlTrainJob)

if err != nil {
return nil, fmt.Errorf("resty GetTrainJobList: %v", err)
}

if res.StatusCode() == http.StatusUnauthorized && retry < 1 {
retry++
_ = getToken()
goto sendjob
}

if res.StatusCode() != http.StatusOK {
var temp models.ErrorResult
if err = json.Unmarshal([]byte(res.String()), &temp); err != nil {
log.Error("json.Unmarshal failed(%s): %v", res.String(), err.Error())
return &result, fmt.Errorf("json.Unmarshal failed(%s): %v", res.String(), err.Error())
}
log.Error("GetTrainJobList failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
return &result, fmt.Errorf(temp.ErrorMsg)
}

if !result.IsSuccess {
log.Error("GetTrainJobList failed(%s): %s", result.ErrorCode, result.ErrorMsg)
return &result, fmt.Errorf(result.ErrorMsg)
}

return &result, nil
}

func GetTrainJobVersionList(perPage, page int, jobID string) (*models.GetTrainJobVersionListResult, error) {
checkSetting()
client := getRestyClient()
var result models.GetTrainJobVersionListResult

retry := 0

sendjob:
res, err := client.R().
SetQueryParams(map[string]string{
"per_page": strconv.Itoa(perPage),
"page": strconv.Itoa(page),
}).
SetAuthToken(TOKEN).
SetResult(&result).
Get(HOST + "/v1/" + setting.ProjectID + urlTrainJob + "/" + jobID + "/versions")

if err != nil {
return nil, fmt.Errorf("resty GetTrainJobVersionList: %v", err)
}

if res.StatusCode() == http.StatusUnauthorized && retry < 1 {
retry++
_ = getToken()
goto sendjob
}

if res.StatusCode() != http.StatusOK {
var temp models.ErrorResult
if err = json.Unmarshal([]byte(res.String()), &temp); err != nil {
log.Error("json.Unmarshal failed(%s): %v", res.String(), err.Error())
return &result, fmt.Errorf("json.Unmarshal failed(%s): %v", res.String(), err.Error())
}
log.Error("GetTrainJobVersionList failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
return &result, fmt.Errorf(temp.ErrorMsg)
}

if !result.IsSuccess {
log.Error("GetTrainJobVersionList failed(%s): %s", result.ErrorCode, result.ErrorMsg)
return &result, fmt.Errorf(result.ErrorMsg)
}

return &result, nil
}

func GetNotebookList(limit, offset int, sortBy, order, searchContent string) (*models.GetNotebookListResult, error) {
checkSetting()
client := getRestyClient()
var result models.GetNotebookListResult

retry := 0

sendjob:
res, err := client.R().
SetQueryParams(map[string]string{
"limit": strconv.Itoa(limit),
"offset": strconv.Itoa(offset),
"name": searchContent,
"sort_key": sortBy,
"sort_dir": order,
}).
SetAuthToken(TOKEN).
SetResult(&result).
Get(HOST + "/v1/" + setting.ProjectID + urlNotebook2)

if err != nil {
return nil, fmt.Errorf("resty GetNotebookList: %v", err)
}

if res.StatusCode() == http.StatusUnauthorized && retry < 1 {
retry++
_ = getToken()
goto sendjob
}

if res.StatusCode() != http.StatusOK {
var temp models.ErrorResult
if err = json.Unmarshal([]byte(res.String()), &temp); err != nil {
log.Error("json.Unmarshal failed(%s): %v", res.String(), err.Error())
return &result, fmt.Errorf("json.Unmarshal failed(%s): %v", res.String(), err.Error())
}
log.Error("GetNotebookList failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
return &result, fmt.Errorf(temp.ErrorMsg)
}

return &result, nil
}

+ 5
- 13
modules/notification/wechat/wechat.go View File

@@ -7,8 +7,8 @@ package wechat
import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/auth/wechat"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/notification/base"
"code.gitea.io/gitea/modules/setting"
)

type wechatNotifier struct {
@@ -25,20 +25,12 @@ func NewNotifier() base.Notifier {
}

func (*wechatNotifier) NotifyChangeCloudbrainStatus(cloudbrain *models.Cloudbrain, oldStatus string) {
log.Info("NotifyChangeCloudbrainStatus cloudbrain.id=%d cloudbrain.status=%s oldStatus=%s", cloudbrain.ID, cloudbrain.Status, oldStatus)
operateType := wechat.GetJobOperateTypeFromCloudbrainStatus(cloudbrain)
if operateType == "" {
log.Info("NotifyChangeCloudbrainStatus operateType is incorrect")
return
}
switch operateType {
case wechat.JobOperateTypeStart:
if len(setting.CloudbrainStartedNotifyList) == 0 {
return
}
for _, v := range setting.CloudbrainStartedNotifyList {
if v == cloudbrain.JobType {
go wechat.SendCloudbrainStartedMsg(operateType, *cloudbrain)
return
}
}
}
template := wechat.GetTemplateFromOperateType(operateType)
go wechat.SendTemplateMsg(template, &wechat.TemplateContext{Cloudbrain: cloudbrain}, cloudbrain.UserID)
}

+ 2
- 0
modules/setting/cloudbrain.go View File

@@ -5,6 +5,7 @@ type CloudbrainLoginConfig struct {
Password string
Host string
ImageURLPrefix string
Expiration string
}

var (
@@ -17,5 +18,6 @@ func GetCloudbrainConfig() CloudbrainLoginConfig {
Cloudbrain.Password = cloudbrainSec.Key("PASSWORD").MustString("")
Cloudbrain.Host = cloudbrainSec.Key("REST_SERVER_HOST").MustString("")
Cloudbrain.ImageURLPrefix = cloudbrainSec.Key("IMAGE_URL_PREFIX").MustString("")
Cloudbrain.Expiration = cloudbrainSec.Key("EXPIRATION").MustString("604800")
return Cloudbrain
}

+ 5
- 2
modules/setting/repository.go View File

@@ -193,8 +193,9 @@ var (
Wiki: []string{"never"},
},
}
RepoRootPath string
ScriptType = "bash"
RepoRootPath string
RepoMaxReferenceDatasetNum int
ScriptType = "bash"
)

func newRepository() {
@@ -210,6 +211,8 @@ func newRepository() {
Repository.UseCompatSSHURI = sec.Key("USE_COMPAT_SSH_URI").MustBool()
Repository.MaxCreationLimit = sec.Key("MAX_CREATION_LIMIT").MustInt(-1)
RepoRootPath = sec.Key("ROOT").MustString(path.Join(homeDir, "gitea-repositories"))
RepoMaxReferenceDatasetNum = sec.Key("MAX_REF_DATASET_NUM").MustInt(20)

forcePathSeparator(RepoRootPath)
if !filepath.IsAbs(RepoRootPath) {
RepoRootPath = filepath.Join(AppWorkPath, RepoRootPath)


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

@@ -539,6 +539,7 @@ var (
DebugHost string
ImageInfos string
Capacity int
MaxTempQueryTimes int
//train-job
ResourcePools string
Engines string
@@ -586,6 +587,12 @@ var (
//wechat template msg config
CloudbrainStartedTemplateId string
CloudbrainStartedNotifyList []string
CloudbrainStartedTitle string
CloudbrainStartedRemark string
CloudbrainStoppedTemplateId string
CloudbrainStoppedNotifyList []string
CloudbrainStoppedTitle string
CloudbrainStoppedRemark string

//nginx proxy
PROXYURL string
@@ -1418,6 +1425,7 @@ func NewContext() {
Flavor = sec.Key("FLAVOR").MustString("")
ImageInfos = sec.Key("IMAGE_INFOS").MustString("")
Capacity = sec.Key("IMAGE_INFOS").MustInt(100)
MaxTempQueryTimes = sec.Key("MAX_TEMP_QUERY_TIMES").MustInt(30)
ResourcePools = sec.Key("Resource_Pools").MustString("")
Engines = sec.Key("Engines").MustString("")
EngineVersions = sec.Key("Engine_Versions").MustString("")
@@ -1448,6 +1456,12 @@ func NewContext() {
TreePathOfSubscribe = sec.Key("SUBSCRIBE_TREE_PATH").MustString("wechat/subscribe_reply.json")
CloudbrainStartedTemplateId = sec.Key("CLOUDBRAIN_STARTED_TEMPLATE_ID").MustString("")
CloudbrainStartedNotifyList = strings.Split(sec.Key("CLOUDBRAIN_STARTED_NOTIFY_LIST").MustString("DEBUG"), ",")
CloudbrainStartedTitle = sec.Key("CLOUDBRAIN_STARTED_TITLE").MustString("您好,您提交的算力资源申请已通过,任务已启动,请您关注运行情况。")
CloudbrainStartedRemark = sec.Key("CLOUDBRAIN_STARTED_REMARK").MustString("感谢您的耐心等待。")
CloudbrainStoppedTemplateId = sec.Key("CLOUDBRAIN_STOPPED_TEMPLATE_ID").MustString("")
CloudbrainStoppedNotifyList = strings.Split(sec.Key("CLOUDBRAIN_STOPPED_NOTIFY_LIST").MustString("TRAIN"), ",")
CloudbrainStoppedTitle = sec.Key("CLOUDBRAIN_STOPPED_TITLE").MustString("您好,您申请的算力资源已结束使用,任务已完成运行,请您关注运行结果。")
CloudbrainStoppedRemark = sec.Key("CLOUDBRAIN_STOPPED_REMARK").MustString("感谢您的耐心等待。")

SetRadarMapConfig()



+ 0
- 41
modules/storage/minio_ext.go View File

@@ -214,47 +214,6 @@ func GetOneLevelAllObjectUnderDirMinio(bucket string, prefixRootPath string, rel
ParenDir: ParenDir,
}
fileInfos = append(fileInfos, fileInfo)

// log.Info("val key=" + val.Key)
// var isDir bool
// var fileName string
// if val.Key == Prefix {
// continue
// }

// fileName = val.Key[prefixLen:]
// log.Info("fileName =" + fileName)
// files := strings.Split(fileName, "/")
// if fileMap[files[0]] {
// continue
// } else {
// fileMap[files[0]] = true
// }
// ParenDir := relativePath
// fileName = files[0]
// if len(files) > 1 {
// isDir = true
// ParenDir += fileName + "/"
// } else {
// isDir = false
// }

// // if strings.HasSuffix(val.Key, "/") {
// // isDir = true
// // fileName = val.Key[prefixLen : len(val.Key)-1]
// // relativePath += val.Key[prefixLen:]
// // } else {
// // isDir = false
// // fileName = val.Key[prefixLen:]
// // }
// fileInfo := FileInfo{
// ModTime: val.LastModified.Local().Format("2006-01-02 15:04:05"),
// FileName: fileName,
// Size: val.Size,
// IsDir: isDir,
// ParenDir: relativePath,
// }
// fileInfos = append(fileInfos, fileInfo)
}
return fileInfos, err
} else {


+ 27
- 24
modules/templates/helper.go View File

@@ -97,23 +97,24 @@ func NewFuncMap() []template.FuncMap {
"AllowedReactions": func() []string {
return setting.UI.Reactions
},
"AvatarLink": models.AvatarLink,
"Safe": Safe,
"SafeJS": SafeJS,
"Str2html": Str2html,
"subOne": subOne,
"TimeSince": timeutil.TimeSince,
"TimeSinceUnix": timeutil.TimeSinceUnix,
"TimeSinceUnix1": timeutil.TimeSinceUnix1,
"AttachmentResourceType": dataset.GetResourceType,
"AttachmentStatus": dataset.GetStatusText,
"TimeSinceUnixShort": timeutil.TimeSinceUnixShort,
"RawTimeSince": timeutil.RawTimeSince,
"FileSize": base.FileSize,
"PrettyNumber": base.PrettyNumber,
"Subtract": base.Subtract,
"EntryIcon": base.EntryIcon,
"MigrationIcon": MigrationIcon,
"AvatarLink": models.AvatarLink,
"Safe": Safe,
"SafeJS": SafeJS,
"Str2html": Str2html,
"subOne": subOne,
"TimeSince": timeutil.TimeSince,
"TimeSinceUnix": timeutil.TimeSinceUnix,
"TimeSinceUnix1": timeutil.TimeSinceUnix1,
"AttachmentResourceType": dataset.GetResourceType,
"AttachmentStatus": dataset.GetStatusText,
"IsShowDataSetOfCurrentRepo": dataset.IsShowDataSetOfCurrentRepo,
"TimeSinceUnixShort": timeutil.TimeSinceUnixShort,
"RawTimeSince": timeutil.RawTimeSince,
"FileSize": base.FileSize,
"PrettyNumber": base.PrettyNumber,
"Subtract": base.Subtract,
"EntryIcon": base.EntryIcon,
"MigrationIcon": MigrationIcon,
"Add": func(a, b int) int {
return a + b
},
@@ -357,13 +358,15 @@ func NewTextFuncMap() []texttmpl.FuncMap {
"AppDomain": func() string {
return setting.Domain
},
"TimeSince": timeutil.TimeSince,
"TimeSinceUnix": timeutil.TimeSinceUnix,
"TimeSinceUnix1": timeutil.TimeSinceUnix1,
"TimeSinceUnixShort": timeutil.TimeSinceUnixShort,
"RawTimeSince": timeutil.RawTimeSince,
"AttachmentResourceType": dataset.GetResourceType,
"AttachmentStatus": dataset.GetStatusText,
"TimeSince": timeutil.TimeSince,
"TimeSinceUnix": timeutil.TimeSinceUnix,
"TimeSinceUnix1": timeutil.TimeSinceUnix1,
"TimeSinceUnixShort": timeutil.TimeSinceUnixShort,
"RawTimeSince": timeutil.RawTimeSince,
"AttachmentResourceType": dataset.GetResourceType,
"AttachmentStatus": dataset.GetStatusText,
"IsShowDataSetOfCurrentRepo": dataset.IsShowDataSetOfCurrentRepo,

"DateFmtLong": func(t time.Time) string {
return t.Format(time.RFC1123Z)
},


+ 88
- 19
options/locale/locale_en-US.ini View File

@@ -98,6 +98,7 @@ error500= Sorry, the site has encountered some problems, we are trying to <stron
[error]
occurred = An error has occurred
report_message = An error has occurred
no_right=You have no right to do the operation.

[install]
install = Installation
@@ -253,12 +254,15 @@ page_dev_env_desc2_desc=Associate the model with the code version, you can adjus
page_dev_env_desc3_title=Once Configuration, Multiple Reuse
page_dev_env_desc3_desc=Provide execution environment sharing, Once Configuration, Multiple Reuse. Lower the threshold of model development, and avoid spending repetitive time configuring complex environments.
page_dev_yunlao=OpenI AI Collaboration Platform
page_dev_yunlao_desc1=OpenI AI collaboration platform has been connected with Pengcheng CloudBrain and China computing network (c2net) in phase I, and can use the rich computing resources of Pengcheng CloudBrain and China computing network to complete AI development tasks.
page_dev_yunlao_desc2=Pengcheng CloudBrain's existing AI computing power is 100p FLOPS@FP16 (billions of half precision floating-point calculations per second), the main hardware infrastructure is composed of GPU servers equipped with NVIDIA Tesla V100 and A100, and Atlas 900 AI clusters equipped with Kunpeng and shengteng processors; China computing network (c2net) phase I can realize the high-speed network interconnection between different AI computing centers, realize the reasonable scheduling of computing power and the flexible allocation of resources. At present, it has been connected to 11 intelligent computing centers, with a total scale of 1924p.
page_dev_yunlao_desc3=OpenI AI collaboration platform has been connected to Pengcheng Cloud Computing Institute, Chengdu Intelligent Computing Center, Zhongyuan Intelligent Computing Center, Hefei brain and other nodes. Developers can freely choose the corresponding computing resources according to their use needs, and can test the adaptability, performance, stability, etc. of the model in different hardware environments.
page_dev_yunlao_desc4=If your model requires more computing resources, you can also apply for it separately.
page_dev_yunlao_desc1=OpenI AI collaboration platform has cooperated with Pengcheng cloud brain and China computing power network (C²NET) can be used to complete AI development tasks by using the rich computing resources of Pengcheng cloud brain and China computing network.
page_dev_yunlao_desc2=Pengcheng CloudBrain's existing AI computing power is 100p FLOPS@FP16 (billions of half precision floating-point calculations per second), the main hardware infrastructure consists of GPU servers equipped with NVIDIA Tesla V100 and A100, and Atlas 900 AI clusters equipped with Kunpeng and shengteng processors.
page_dev_yunlao_desc3=China computing power network (C²NET) phase I can realize high-speed network interconnection between different artificial intelligence computing centers, and realize reasonable scheduling of computing power and flexible allocation of resources. At present, 11 intelligent computing centers have been connected, and the total scale of computing power is 1924p OPS@FP16. OpenI AI collaboration platform has been connected to Pengcheng Cloud Computing Institute, Chengdu Intelligent Computing Center, Zhongyuan Intelligent Computing Center, Hefei brain and other nodes.
page_dev_yunlao_desc4=Developers can freely select the corresponding computing resources according to the use needs, and can test the adaptability, performance, stability, etc. of the model in different hardware environments.
page_dev_yunlao_desc5=If your model requires more computing resources, you can also apply for it separately.
page_dev_yunlao_apply=Apply Separately

c2net_title=China Computing Network
c2net_desc=The artificial intelligence computing power network promotion alliance has access to 11 intelligent computing centers, with a total scale of 1924p.
c2net_center=Center
search=Search
search_repo=Repository
search_dataset=DataSet
@@ -821,6 +825,9 @@ title_format_err=Name can only contain number,letter,'-','_' or '.', and can be
description = Description
description_format_err=Description's length can be up to %s characters long.
create_dataset = Create Dataset
download_url=Download Url
download_oper=Operation
download_copy=Copy URL
create_dataset_fail=Failed to create dataset.
query_dataset_fail=Failed to query dataset.
edit_attachment_fail=Failed to update description.
@@ -831,6 +838,8 @@ category = Category
no_category = No Category
task = Task
no_task = No Task
reference_dataset_fail=Failed to reference dataset, please try again later.
cancel_reference_dataset_fail=Failed to cancel reference dataset, please try again later.
license = License
no_license = No License
file = Dataset File
@@ -914,9 +923,10 @@ select_task = Select Research Direction/Application Area
dataset_name_tooltips = Please enter letters, numbers, _ and - up to 100 characters.
dataset_no_create = No dataset has been created yet
dataset_explain = Dataset: CloudBrain I provides CPU/GPU resources, Cloudbrain II provides Ascend NPU resources, and the data set used for debugging also needs to be uploaded to the corresponding environment;
dataset_instructions_for_use = Instructions for use: You can refer to Qizhi AI Collaboration Platform
dataset_camp_course = Newcomer Training Camp Course;
dataset_instructions_for_use = Instructions for use: You can refer to Openi AI Collaboration Platform
dataset_camp_course = Newcomer Training Camp Course;
dataset_upload = Upload
dataset_upload_status= Upload Status
dataset_file_name = File Name
dataset_available_clusters = Available Clusters
dataset_upload_time = Upload Time
@@ -943,6 +953,13 @@ unzip_failed=Unzip Failed
unzip_stared=Unzipping
unzip_status=Unzip Status
collection_num=Collection Nums
current_dataset=Current Dataset
linked_dataset=Linked Dataset
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.

[repo]
owner = Owner
repo_name = Repository Name
@@ -1073,6 +1090,7 @@ cloudbrain_operate = Operate
cloudbrain_status_createtime = Status/Createtime
cloudbrain_status_runtime = Running Time
cloudbrain_jobname_err=Name must start with a lowercase letter or number,can include lowercase letter,number,_ and -,can not end with _, and can be up to 36 characters long.
cloudbrain_bootfile_err=The bootfile does not exist in the repository
cloudbrain_query_fail=Failed to query cloudbrain information.
cloudbrain.mirror_tag = Mirror Tag
cloudbrain.mirror_description = Mirror Description
@@ -1097,7 +1115,8 @@ modelarts.status=Status
modelarts.createtime=CreateTime
modelarts.version_nums = Version Nums
modelarts.version = Version
modelarts.computing_resources=compute Resources
modelarts.computing_resources=Compute Resources
modelarts.cluster.computing_resources=Cluster/Compute Resources
modelarts.ai_center=Ai Center
modelarts.card_type=Card Type
modelarts.cluster=Cluster
@@ -1190,7 +1209,7 @@ modelarts.infer_job_model_file = Model File
modelarts.infer_job = Inference Job
modelarts.infer_job.model_version = Model/Version
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.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

@@ -1202,7 +1221,7 @@ 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">Xiaobai training camp </a> course of Qizhi AI collaboration platform.
platform_instructions = Instructions for use: You can refer to the <a href="https://git.openi.org.cn/zeizei/OpenI_Learning">Xiaobai training camp </a> 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

@@ -1213,7 +1232,7 @@ model.manage.version = Version
model.manage.label = Label
model.manage.size = Size
model.manage.create_time = Create Time
model.manage.Description = Description
model.manage.description = Description
model.manage.Accuracy = Accuracy
model.manage.F1 = F1
model.manage.Precision = Precision
@@ -1225,6 +1244,49 @@ 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.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.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
model.manage.select.version=Select version
model.manage.engine=Model engine
model.manage.select.engine=Select model engine
model.manage.modelfile=Model file
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.download=Download
modelconvert.taskname=Task name
modelconvert.modelname=Model name
modelconvert.selectmodel=Select model
modelconvert.modelversion=Model version
modelconvert.selectversion=Select version
modelconvert.selectmodelfile=Select model file
modelconvert.taskstatus=Status
modelconvert.srcengine=Source model engine
modelconvert.outputformat=Output format
modelconvert.createtime=Created time
modelconvert.inputdataformat=Input data format
modelconvert.inputshape=Input tensor shape
modelconvert.inputshapetip=For example: 1,1,32,32, corresponding to the input data format.
modelconvert.netoutputdata=Network output data type
modelconvert.taskdesc=Task description
modelconvert.newtask=New
modelconvert.createtask=Create model transformation task
modelconvert.taskurlname=Model transformation task
log_scroll_start=Scroll to top
log_scroll_end=Scroll to bottom
modelconvert.tasknameempty=Please enter a task name.
modelconvert.inputshapeerror=Format input error, please input such as: 1,1,32,32, corresponding to the input data format.

modelconvert.manage.create_error1=A model transformation task with the same name already exists.
modelconvert.manage.create_error2=Only one running model transformation task can be created.
modelconvert.manage.model_not_exist=The model does not exist.
@@ -2321,7 +2383,7 @@ topic.count_prompt = You can not select more than 25 topics
topic.format_prompt = Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.
imagetopic.format_prompt = Topics can be up to 35 characters long.
use_repo_agreement=I promise that the content of this warehouse does not violate any national laws and regulations. During the use of the warehouse, I will abide by the OpenI community management regulations and platform usage rules, and will not conduct malicious attacks, mining, or any other illegal or disruptive platform order. Information release and related behaviors. For more information please refer to
openi_use_agreement=OpenI Qizhi Community Platform Use Agreement.
openi_use_agreement=OpenI Openi Community Platform Use Agreement.
[org]
org_name_holder = Organization Name
org_full_name_holder = Organization Full Name
@@ -2995,15 +3057,15 @@ mirror_sync_delete = synced and deleted reference <code>%[2]s</code> at <a href=
approve_pull_request = `approved <a href="%s/pulls/%s">%s#%[2]s</a>`
reject_pull_request = `suggested changes for <a href="%s/pulls/%s">%s#%[2]s</a>`
upload_dataset=`upload dataset <a href="%s/datasets">%s</a>`
task_gpudebugjob=`created CPU/GPU type debugging task<a href="%s/cloudbrain/%s">%s</a>`
task_gpudebugjob=`created CPU/GPU type debugging task <a href="%s/cloudbrain/%s">%s</a>`
task_npudebugjob=`created NPU type debugging task <a href="%s/modelarts/notebook/%s">%s</a>`
task_nputrainjob=`created NPU training task<a href="%s/modelarts/train-job/%s">%s</a>`
task_nputrainjob=`created NPU training task <a href="%s/modelarts/train-job/%s">%s</a>`
task_inferencejob=`created reasoning task <a href="%s/modelarts/inference-job/%s">%s</a>`
task_benchmark=`created profiling task <a href="%s/cloudbrain/benchmark/%s">%s</a>`
task_createmodel=`created new model <a href="%s/modelmanage/show_model_info?name=%s">%s</a>`
task_gputrainjob=`created CPU/GPU training task<a href="%s/cloudbrain/train-job/%s">%s</a>`
task_c2netnputrainjob=`created NPU training task<a href="%s/grampus/train-job/%s">%s</a>`
task_c2netgputrainjob=`created CPU/GPU training task<a href="%s/grampus/train-job/%s">%s</a>`
task_gputrainjob=`created CPU/GPU training task <a href="%s/cloudbrain/train-job/%s">%s</a>`
task_c2netnputrainjob=`created NPU training task <a href="%s/grampus/train-job/%s">%s</a>`
task_c2netgputrainjob=`created CPU/GPU training task <a href="%s/grampus/train-job/%s">%s</a>`

[tool]
ago = %s ago
@@ -3092,9 +3154,13 @@ Platform_Tutorial = Tutorial
foot.advice_feedback = Feedback

[cloudbrain]
all_resource_cluster=All Cluster
all_ai_center=All Computing NET
resource_cluster = Resource Cluster
resource_cluster_openi = OpenI Resource Cluster
resource_cluster_c2net = China Computing NET
resource_cluster_openi_simple = OpenI
resource_cluster_c2net_simple = C²NET
compute_resource = Computing resources
task_name = Task name
task_type = Task type
@@ -3116,10 +3182,11 @@ specification = specification
select_specification = select specification
description = description
wrong_specification=You cannot use this specification, please choose another item.
resource_use=Resource Occupancy

job_name_rule = Please enter letters, numbers, _ and - up to 64 characters and cannot end with a dash (-).
dataset_path_rule = The dataset location is stored in the environment variable data_url, and the training output path is stored in the environment variable train_url.
train_dataset_path_rule = The dataset location is stored in the environment variable <strong style="color:#010101">data_url</strong>, and the output path is stored in the environment variable <strong style="color:#010101">train_url</strong>.
infer_dataset_path_rule = The dataset location is stored in the environment variable <strong style="color:#010101">data_url</strong>, and the output path is stored in the environment variable <strong style="color:#010101">result_url</strong>.
view_sample = View sample
inference_output_path_rule = The inference output path is stored in the environment variable result_url.
model_file_path_rule=The model file location is stored in the environment variable ckpt_url
@@ -3152,3 +3219,5 @@ Stopped_success_update_status_fail=Succeed in stopping th job, but failed to upd
load_code_failed=Fail to load code, please check if the right branch is selected.

error.dataset_select = dataset select error:the count exceed the limit or has same name
new_train_gpu_tooltips = The code is storaged in <strong style="color:#010101">%s</strong>, the dataset is storaged in <strong style="color:#010101">%s</strong>, and please put your model into <strong style="color:#010101">%s</strong> then you can download it online
new_infer_gpu_tooltips = The dataset is stored in <strong style="color:#010101">%s</strong>, the model file is stored in <strong style="color:#010101">%s</strong>, please store the inference output in <strong style="color:#010101">%s</strong> for subsequent downloads.

+ 78
- 7
options/locale/locale_zh-CN.ini View File

@@ -99,6 +99,7 @@ error500=抱歉,站点遇到一些问题,我们正尝试<strong>修复网页
[error]
occurred=发生错误
report_message=发生错误
no_right=您没有权限执行本操作。

[install]
install=安装页面
@@ -255,12 +256,15 @@ page_dev_env_desc2_desc=将模型与代码版本建立关联,可以基于代
page_dev_env_desc3_title=一次配置,多次使用
page_dev_env_desc3_desc=提供执行环境共享,一次配置,多次使用,降低模型开发门槛,避免花费重复的时间配置复杂的环境
page_dev_yunlao=启智AI协作平台
page_dev_yunlao_desc1=启智AI协作平台已经与鹏城云脑、中国算力网(C2Net)一期打通,可以利用鹏城云脑和中国算力网的丰富算力资源,完成AI开发任务。
page_dev_yunlao_desc2=鹏城云脑现有AI算力100P FLOPS@FP16(每秒十亿亿次半精度浮点计算),主要硬件基础设施由搭载英伟达Tesla V100 和A100 的GPU服务器,以及搭载鲲鹏、昇腾处理器的Atlas 900 AI集群构成;中国算力网(C2Net)一期可实现不同人工智能计算中心之间高速网络互联,实现算力合理调度和资源弹性分配,目前已接入11家智算中心,算力总规模1924P。
page_dev_yunlao_desc3=启智AI协作平台已接入其中的鹏城云计算所、成都智算中心、中原智算中心、合肥类脑等节点,开发者可以根据使用需求,自由选择相应计算资源,可以测试模型在不同硬件环境下的适配能力、性能、稳定性等。
page_dev_yunlao_desc4=如果您的模型需要更多的计算资源,也可以单独申请。
page_dev_yunlao_desc1=启智AI协作平台已经与鹏城云脑、中国算力网(C²NET)一期打通,可以利用鹏城云脑和中国算力网的丰富算力资源,完成AI开发任务。
page_dev_yunlao_desc2=鹏城云脑现有AI算力100P FLOPS@FP16(每秒十亿亿次半精度浮点计算),主要硬件基础设施由搭载英伟达Tesla V100 和A100 的GPU服务器,以及搭载鲲鹏、昇腾处理器的Atlas 900 AI集群构成。
page_dev_yunlao_desc3=中国算力网(C²NET)一期可实现不同人工智能计算中心之间高速网络互联,实现算力合理调度和资源弹性分配。目前已接入11家智算中心,算力总规模1924P OPS@FP16。启智AI协作平台已接入其中的鹏城云计算所、成都智算中心、中原智算中心、合肥类脑等节点。
page_dev_yunlao_desc4=开发者可以根据使用需求,自由选择相应计算资源,可以测试模型在不同硬件环境下的适配能力、性能、稳定性等。
page_dev_yunlao_desc5=如果您的模型需要更多的计算资源,也可以单独申请。
page_dev_yunlao_apply=单独申请

c2net_title=智算网络
c2net_desc=人工智能算力网络推进联盟已接入11家智算中心,算力总规模1924P
c2net_center=中心
search=搜索
search_repo=项目
search_dataset=数据集
@@ -830,6 +834,12 @@ create_dataset_fail=创建数据集失败。
query_dataset_fail=查询数据集失败。
edit_attachment_fail=修改描述失败。

reference_dataset_fail=关联数据集失败,请稍后再试。
cancel_reference_dataset_fail=取消关联数据集失败,请稍后再试。

download_url=数据集下载地址
download_copy=复制链接
download_oper=操作
show_dataset=数据集
edit_dataset=编辑数据集
update_dataset=更新数据集
@@ -922,6 +932,7 @@ dataset_explain = 数据集:云脑1提供 CPU / GPU 资源,云脑2提供 Asc
dataset_instructions_for_use = 使用说明:可以参考启智AI协作平台
dataset_camp_course = 小白训练营课程
dataset_upload = 上传
dataset_upload_status = 上传状态
dataset_file_name = 文件名称
dataset_available_clusters = 可用集群
dataset_upload_time = 上传时间
@@ -948,6 +959,13 @@ unzip_failed=解压失败
unzip_stared=解压中
unzip_status=解压状态
collection_num=收藏数量
current_dataset=当前数据集
linked_dataset=关联数据集
unfavorite=取消收藏
favorite=收藏
disassociate=取消关联
benchmark_dataset_tip=说明:先使用数据集功能上传模型,然后从数据集列表选模型。

[repo]
owner=拥有者
repo_name=项目名称
@@ -1076,6 +1094,7 @@ cloudbrain_operate=操作
cloudbrain_status_createtime=状态/创建时间
cloudbrain_status_runtime = 运行时长
cloudbrain_jobname_err=只能以小写字母或数字开头且只包含小写字母、数字、_和-,不能以_结尾,最长36个字符。
cloudbrain_bootfile_err=仓库中不存在启动文件
cloudbrain_query_fail=查询云脑任务失败。
cloudbrain.mirror_tag = 镜像标签
cloudbrain.mirror_description = 镜像描述
@@ -1108,6 +1127,7 @@ modelarts.deletetime=删除时间
modelarts.version_nums=版本数
modelarts.version=版本
modelarts.computing_resources=计算资源
modelarts.cluster.computing_resources=集群/计算资源
modelarts.ai_center=智算中心
modelarts.card_type=卡类型
modelarts.cluster=集群
@@ -1237,6 +1257,50 @@ model.convert=模型转换任务
model.list=模型列表
model.manage.create_new_convert_task=创建模型转换任务

model.manage.notcreatemodel=未创建过模型
model.manage.init1=代码版本:您还没有初始化代码仓库,请先
model.manage.init2=创建代码版本;
model.manage.createtrainjob_tip=训练任务:您还没创建过训练任务,请先创建
model.manage.createtrainjob=训练任务
model.manage.delete=删除模型
model.manage.delete_confirm=你确认删除该模型么?此模型一旦删除不可恢复。
model.manage.select.trainjob=选择训练任务
model.manage.select.version=选择版本
model.manage.engine=模型框架
model.manage.select.engine=选择模型框架
model.manage.modelfile=模型文件
model.manage.modellabel=模型标签
model.manage.modeldesc=模型描述
model.manage.baseinfo=基本信息
modelconvert.notcreate=未创建过模型转换任务
modelconvert.importfirst1=请您先导入
modelconvert.importfirst2=模型下载
modelconvert.importfirst3=,然后再对其进行转换。
modelconvert.download=下载
modelconvert.taskname=任务名称
modelconvert.modelname=模型名称
modelconvert.selectmodel=选择模型
modelconvert.modelversion=模型版本
modelconvert.selectversion=选择版本
modelconvert.selectmodelfile=选择模型文件
modelconvert.taskstatus=状态
modelconvert.srcengine=原模型框架
modelconvert.outputformat=转换后格式
modelconvert.createtime=创建时间
modelconvert.inputdataformat=输入数据格式
modelconvert.inputshape=输入张量形状
modelconvert.inputshapetip=如:1,1,32,32,与输入数据格式对应。
modelconvert.netoutputdata=网络输出数据类型
modelconvert.taskdesc=任务描述
modelconvert.newtask=新建任务
modelconvert.createtask=创建模型转换任务

modelconvert.taskurlname=模型转换任务
log_scroll_start=滚动到顶部
log_scroll_end=滚动到底部
modelconvert.tasknameempty=请输入任务名称。
modelconvert.inputshapeerror=格式输入错误,请输入如:1,1,32,32,与输入数据格式对应。

modelconvert.manage.create_error1=相同的名称模型转换任务已经存在。
modelconvert.manage.create_error2=只能创建一个正在运行的模型转换任务。
modelconvert.manage.model_not_exist=选择的模型不存在。
@@ -3106,9 +3170,13 @@ Platform_Tutorial=新手指引
foot.advice_feedback = 意见反馈

[cloudbrain]
all_resource_cluster=全部集群
all_ai_center=全部智算中心
resource_cluster = 算力集群
resource_cluster_openi = 启智集群
resource_cluster_c2net = 智算网络集群
resource_cluster_openi_simple = 启智
resource_cluster_c2net_simple = 智算网络
compute_resource = 计算资源
task_name = 任务名称
task_type = 任务类型
@@ -3134,7 +3202,8 @@ card_type = 卡类型
wrong_specification=您目前不能使用这个资源规格,请选择其他资源规格。

job_name_rule = 请输入字母、数字、_和-,最长64个字符,且不能以中划线(-)结尾。
dataset_path_rule = 数据集位置存储在环境变量data_url中,训练输出路径存储在环境变量train_url中。
train_dataset_path_rule = 数据集位置存储在环境变量<strong style="color:#010101">data_url</strong>中,训练输出路径存储在环境变量<strong style="color:#010101">train_url</strong>中。
infer_dataset_path_rule = 数据集位置存储在环境变量<strong style="color:#010101">data_url</strong>中,推理输出路径存储在环境变量<strong style="color:#010101">result_url</strong>中。
view_sample = 查看样例
inference_output_path_rule = 推理输出路径存储在环境变量result_url中。
model_file_path_rule = 模型文件位置存储在环境变量ckpt_url中。
@@ -3144,7 +3213,7 @@ delete_task = 删除任务
task_delete_confirm = 你确认删除该任务么?此任务一旦删除不可恢复。
operate_confirm = 确定操作
operate_cancel = 取消操作
resource_use=资源占用情况

gpu_num = GPU数
cpu_num = CPU数
@@ -3168,3 +3237,5 @@ load_code_failed=代码加载失败,请确认选择了正确的分支。


error.dataset_select = 数据集选择错误:数量超过限制或者有同名数据集
new_train_gpu_tooltips =训练脚本存储在<strong style="color:#010101">%s</strong>中,数据集存储在<strong style="color:#010101">%s</strong>中,训练输出请存储在<strong style="color:#010101">%s</strong>中以供后续下载。
new_infer_gpu_tooltips = 数据集存储在<strong style="color:#010101">%s</strong>中,模型文件存储在<strong style="color:#010101">%s</strong>中,推理输出请存储在<strong style="color:#010101">%s</strong>中以供后续下载。

+ 6
- 0
routers/admin/cloudbrains.go View File

@@ -35,10 +35,14 @@ func CloudBrains(ctx *context.Context) {
listType := ctx.Query("listType")
jobType := ctx.Query("jobType")
jobStatus := ctx.Query("jobStatus")
aiCenter := ctx.Query("aiCenter")
cluster := ctx.Query("cluster")

ctx.Data["ListType"] = listType
ctx.Data["JobType"] = jobType
ctx.Data["JobStatus"] = jobStatus
ctx.Data["aiCenter"] = aiCenter
ctx.Data["cluster"] = cluster

page := ctx.QueryInt("page")
if page <= 0 {
@@ -80,6 +84,8 @@ func CloudBrains(ctx *context.Context) {
IsLatestVersion: modelarts.IsLatestVersion,
ComputeResource: listType,
Type: models.TypeCloudBrainAll,
AiCenter: aiCenter,
Cluster: cluster,
})
if err != nil {
ctx.ServerError("Get job failed:", err)


+ 1
- 0
routers/api/v1/api.go View File

@@ -916,6 +916,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Group("/cloudbrain", func() {
m.Get("/:id", repo.GetCloudbrainTask)
m.Get("/:id/log", repo.CloudbrainGetLog)
m.Get("/:id/download_log_file", repo.CloudbrainDownloadLogFile)
m.Group("/train-job", func() {
m.Group("/:jobid", func() {
m.Get("", repo.GetModelArtsTrainJobVersion)


+ 119
- 4
routers/api/v1/repo/cloudbrain.go View File

@@ -6,13 +6,17 @@
package repo

import (
"code.gitea.io/gitea/modules/notification"
"bufio"
"encoding/json"
"io"
"net/http"
"os"
"sort"
"strings"
"time"

"code.gitea.io/gitea/modules/notification"

"code.gitea.io/gitea/modules/setting"

"code.gitea.io/gitea/models"
@@ -366,7 +370,7 @@ func CloudbrainForModelConvertGetLog(ctx *context.Context) {
ctx.JSON(http.StatusOK, result)
}

func CloudbrainGetLog(ctx *context.Context) {
func CloudbrainDownloadLogFile(ctx *context.Context) {
ID := ctx.Params(":id")
job, err := models.GetCloudbrainByID(ID)
if err != nil {
@@ -375,13 +379,124 @@ func CloudbrainGetLog(ctx *context.Context) {
return
}

result := CloudbrainGetLogByJobId(job.JobID, job.JobName)
prefix := "/" + setting.CBCodePathPrefix + job.JobName + "/model"
files, err := storage.GetOneLevelAllObjectUnderDirMinio(setting.Attachment.Minio.Bucket, prefix, "")
if err != nil {
log.Error("query cloudbrain model failed: %v", err)
return
}
fileName := ""
for _, file := range files {
if strings.HasSuffix(file.FileName, "log.txt") {
fileName = file.FileName
break
}
}
if fileName != "" {
url, err := storage.Attachments.PresignedGetURL(prefix+"/"+fileName, fileName)
if err != nil {
log.Error("Get minio get SignedUrl failed: %v", err.Error(), ctx.Data["msgID"])
ctx.ServerError("Get minio get SignedUrl failed", err)
return
}
http.Redirect(ctx.Resp, ctx.Req.Request, url, http.StatusTemporaryRedirect)
}
}

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
}
ctx.JSON(http.StatusOK, result)

re := map[string]interface{}{
"JobID": ID,
"LogFileName": result["FileName"],
"StartLine": startLine,
"EndLine": result["endLine"],
"Content": result["Content"],
"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"
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
fileEndLine := endLine
for _, file := range files {
if strings.HasSuffix(file.FileName, "log.txt") {
fileName = file.FileName
path := storage.GetMinioPath(jobName+"/model/", file.FileName)
log.Info("path=" + path)
reader, err := os.Open(path)
defer reader.Close()
if err == nil {
r := bufio.NewReader(reader)
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
}
if error != nil {
log.Info("read file error." + error.Error())
break
}
if error == nil {
if i >= startLine {
re = re + line
count++
}
}
}
} else {
log.Info("error:" + err.Error())
}
break
}
}

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

func CloudBrainModelConvertList(ctx *context.APIContext) {


+ 5
- 1
routers/api/v1/repo/cloudbrain_dashboard.go View File

@@ -679,6 +679,8 @@ func GetCloudbrainsDetailData(ctx *context.Context) {
jobType := ctx.Query("jobType")
jobStatus := ctx.Query("jobStatus")
cloudBrainType := ctx.QueryInt("Type")
aiCenter := ctx.Query("aiCenter")
needDeleteInfo := ctx.Query("needDeleteInfo")

page := ctx.QueryInt("page")
pageSize := ctx.QueryInt("pagesize")
@@ -724,6 +726,8 @@ func GetCloudbrainsDetailData(ctx *context.Context) {
NeedRepoInfo: true,
BeginTimeUnix: int64(recordBeginTime),
EndTimeUnix: endTime.Unix(),
AiCenter: aiCenter,
NeedDeleteInfo: needDeleteInfo,
})
if err != nil {
ctx.ServerError("Get job failed:", err)
@@ -760,7 +764,7 @@ func GetCloudbrainsDetailData(ctx *context.Context) {

taskDetail.WaitTime = repo.GetCloudbrainWaitTime(ciTasks[i].Cloudbrain)

if ciTasks[i].Cloudbrain.DeletedAt != nilTime {
if ciTasks[i].Cloudbrain.DeletedAt != nilTime || ciTasks[i].Repo == nil {
taskDetail.IsDelete = true
} else {
taskDetail.IsDelete = false


+ 18
- 87
routers/api/v1/repo/modelarts.go View File

@@ -6,13 +6,14 @@
package repo

import (
"code.gitea.io/gitea/modules/notification"
"encoding/json"
"net/http"
"path"
"strconv"
"strings"

"code.gitea.io/gitea/modules/notification"

"code.gitea.io/gitea/modules/grampus"
"code.gitea.io/gitea/modules/setting"

@@ -26,40 +27,6 @@ import (
routerRepo "code.gitea.io/gitea/routers/repo"
)

func GetModelArtsNotebook(ctx *context.APIContext) {
var (
err error
)

jobID := ctx.Params(":jobid")
repoID := ctx.Repo.Repository.ID
job, err := models.GetRepoCloudBrainByJobID(repoID, jobID)
if err != nil {
ctx.NotFound(err)
return
}
result, err := modelarts.GetJob(jobID)
if err != nil {
ctx.NotFound(err)
return
}
oldStatus := job.Status
job.Status = result.Status
if oldStatus != result.Status {
notification.NotifyChangeCloudbrainStatus(job, oldStatus)
}
err = models.UpdateJob(job)
if err != nil {
log.Error("UpdateJob failed:", err)
}

ctx.JSON(http.StatusOK, map[string]interface{}{
"JobID": jobID,
"JobStatus": result.Status,
})

}

func GetModelArtsNotebook2(ctx *context.APIContext) {
var (
err error
@@ -71,33 +38,16 @@ func GetModelArtsNotebook2(ctx *context.APIContext) {
ctx.NotFound(err)
return
}
result, err := modelarts.GetNotebook2(job.JobID)
err = modelarts.HandleNotebookInfo(job)
if err != nil {
ctx.NotFound(err)
return
}
if job.StartTime == 0 && result.Lease.UpdateTime > 0 {
job.StartTime = timeutil.TimeStamp(result.Lease.UpdateTime / 1000)
}
oldStatus := job.Status
job.Status = result.Status
if job.EndTime == 0 && models.IsModelArtsDebugJobTerminal(job.Status) {
job.EndTime = timeutil.TimeStampNow()
}
job.CorrectCreateUnix()
job.ComputeAndSetDuration()
if oldStatus != result.Status {
notification.NotifyChangeCloudbrainStatus(job, oldStatus)
}
err = models.UpdateJob(job)
if err != nil {
log.Error("UpdateJob failed:", err)
}

ctx.JSON(http.StatusOK, map[string]interface{}{
"ID": ID,
"JobName": job.JobName,
"JobStatus": result.Status,
"JobStatus": job.Status,
"JobDuration": job.TrainJobDuration,
})

@@ -189,27 +139,11 @@ func GetModelArtsTrainJobVersion(ctx *context.APIContext) {
}
}
} else if job.Type == models.TypeCloudBrainTwo {
result, err := modelarts.GetTrainJob(jobID, strconv.FormatInt(job.VersionID, 10))
err := modelarts.HandleTrainJobInfo(job)
if err != nil {
ctx.NotFound(err)
return
}

if job.StartTime == 0 && result.StartTime > 0 {
job.StartTime = timeutil.TimeStamp(result.StartTime / 1000)
}
job.Status = modelarts.TransTrainJobStatus(result.IntStatus)
job.Duration = result.Duration / 1000
job.TrainJobDuration = models.ConvertDurationToStr(job.Duration)

if job.EndTime == 0 && models.IsTrainJobTerminal(job.Status) && job.StartTime > 0 {
job.EndTime = job.StartTime.Add(job.Duration)
}
job.CorrectCreateUnix()
err = models.UpdateTrainJobVersion(job)
if err != nil {
log.Error("UpdateJob failed:", err)
}
} else if job.Type == models.TypeC2Net {
result, err := grampus.GetJob(jobID)
if err != nil {
@@ -221,6 +155,7 @@ func GetModelArtsTrainJobVersion(ctx *context.APIContext) {
if job.StartTime == 0 && result.JobInfo.StartedAt > 0 {
job.StartTime = timeutil.TimeStamp(result.JobInfo.StartedAt)
}
oldStatus := job.Status
job.Status = grampus.TransTrainJobStatus(result.JobInfo.Status)
job.Duration = result.JobInfo.RunSec
job.TrainJobDuration = models.ConvertDurationToStr(job.Duration)
@@ -243,6 +178,9 @@ func GetModelArtsTrainJobVersion(ctx *context.APIContext) {
aiCenterName = temp[1]
}
}
if oldStatus != job.Status {
notification.NotifyChangeCloudbrainStatus(job, oldStatus)
}
err = models.UpdateTrainJobVersion(job)
if err != nil {
log.Error("UpdateJob failed:", err)
@@ -415,6 +353,14 @@ func DelTrainJobVersion(ctx *context.APIContext) {
return
}

if task.Status != string(models.ModelArtsTrainJobImageFailed) && task.Status != string(models.ModelArtsTrainJobSubmitFailed) && task.Status != string(models.ModelArtsTrainJobDeleteFailed) &&
task.Status != string(models.ModelArtsTrainJobCompleted) && task.Status != string(models.ModelArtsTrainJobFailed) &&
task.Status != string(models.ModelArtsTrainJobKilled) && task.Status != string(models.ModelArtsTrainJobCanceled) && task.Status != string(models.ModelArtsTrainJobLost) {
log.Error("the job(%s) version has not been stopped", task.JobName)
ctx.NotFound(err)
return
}

//删除modelarts上的记录
_, err = modelarts.DelTrainJobVersion(jobID, strconv.FormatInt(task.VersionID, 10))
if err != nil {
@@ -558,26 +504,11 @@ func GetModelArtsInferenceJob(ctx *context.APIContext) {
ctx.NotFound(err)
return
}
result, err := modelarts.GetTrainJob(jobID, strconv.FormatInt(job.VersionID, 10))
err = modelarts.HandleTrainJobInfo(job)
if err != nil {
ctx.NotFound(err)
return
}
if job.StartTime == 0 && result.StartTime > 0 {
job.StartTime = timeutil.TimeStamp(result.StartTime / 1000)
}
job.Status = modelarts.TransTrainJobStatus(result.IntStatus)
job.Duration = result.Duration / 1000
job.TrainJobDuration = models.ConvertDurationToStr(job.Duration)

if job.EndTime == 0 && models.IsTrainJobTerminal(job.Status) && job.StartTime > 0 {
job.EndTime = job.StartTime.Add(job.Duration)
}
job.CorrectCreateUnix()
err = models.UpdateInferenceJob(job)
if err != nil {
log.Error("UpdateJob failed:", err)
}

ctx.JSON(http.StatusOK, map[string]interface{}{
"JobID": jobID,


+ 7
- 15
routers/home.go View File

@@ -40,7 +40,7 @@ const (
tplExploreImages base.TplName = "explore/images"
tplExploreExploreDataAnalysis base.TplName = "explore/data_analysis"
tplHomeTerm base.TplName = "terms"
tplHomePrivacy base.TplName = "privacy"
tplHomePrivacy base.TplName = "privacy"
)

// Home render home page
@@ -93,6 +93,7 @@ func setRecommendURL(ctx *context.Context) {
ctx.Data["page_dev_yunlao_desc2"] = ctx.Tr("home.page_dev_yunlao_desc2")
ctx.Data["page_dev_yunlao_desc3"] = ctx.Tr("home.page_dev_yunlao_desc3")
ctx.Data["page_dev_yunlao_desc4"] = ctx.Tr("home.page_dev_yunlao_desc4")
ctx.Data["page_dev_yunlao_desc5"] = ctx.Tr("home.page_dev_yunlao_desc5")
ctx.Data["page_dev_yunlao_apply"] = ctx.Tr("home.page_dev_yunlao_apply")
ctx.Data["page_recommend_activity"] = ctx.Tr("home.page_recommend_activity")
ctx.Data["page_recommend_activity_desc"] = ctx.Tr("home.page_recommend_activity_desc")
@@ -295,11 +296,10 @@ func ExploreDatasets(ctx *context.Context) {
// ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled

var (
datasets []*models.Dataset
datasetsWithStar []*models.DatasetWithStar
count int64
err error
orderBy models.SearchOrderBy
datasets []*models.Dataset
count int64
err error
orderBy models.SearchOrderBy
)
page := ctx.QueryInt("page")
if page <= 0 {
@@ -378,14 +378,6 @@ func ExploreDatasets(ctx *context.Context) {
ctx.ServerError("SearchDatasets", err)
return
}
for _, dataset := range datasets {
if !ctx.IsSigned {
datasetsWithStar = append(datasetsWithStar, &models.DatasetWithStar{Dataset: *dataset, IsStaring: false})
} else {
datasetsWithStar = append(datasetsWithStar, &models.DatasetWithStar{Dataset: *dataset, IsStaring: models.IsDatasetStaring(ctx.User.ID, dataset.ID)})
}

}

pager := context.NewPagination(int(count), opts.PageSize, page, 5)
ctx.Data["Keyword"] = opts.Keyword
@@ -396,7 +388,7 @@ func ExploreDatasets(ctx *context.Context) {
pager.SetDefaultParams(ctx)
ctx.Data["Page"] = pager

ctx.Data["Datasets"] = datasetsWithStar
ctx.Data["Datasets"] = repository.ConvertToDatasetWithStar(ctx, datasets)
ctx.Data["Total"] = count
ctx.Data["PageIsDatasets"] = true
ctx.HTML(200, tplExploreDataset)


+ 65
- 55
routers/repo/cloudbrain.go View File

@@ -239,6 +239,7 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) {
codePath := setting.JobPath + jobName + cloudbrain.CodeMountPath
resourceSpecId := form.ResourceSpecId
branchName := form.BranchName
bootFile := strings.TrimSpace(form.BootFile)
repo := ctx.Repo.Repository
tpl := tplCloudBrainNew

@@ -305,6 +306,13 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) {

command := cloudbrain.GetCloudbrainDebugCommand()
if jobType == string(models.JobTypeTrain) {
bootFileExist, err := ctx.Repo.FileExists(bootFile, branchName)
if err != nil || !bootFileExist {
log.Error("Get bootfile error:", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_bootfile_err"), tpl, &form)
return
}
tpl = tplCloudBrainTrainJobNew
commandTrain, err := getTrainJobCommand(form)
if err != nil {
@@ -413,6 +421,7 @@ func CloudBrainInferenceJobCreate(ctx *context.Context, form auth.CreateCloudBra
codePath := setting.JobPath + jobName + cloudbrain.CodeMountPath
resourceSpecId := form.ResourceSpecId
branchName := form.BranchName
bootFile := strings.TrimSpace(form.BootFile)
labelName := form.LabelName
repo := ctx.Repo.Repository

@@ -450,6 +459,14 @@ func CloudBrainInferenceJobCreate(ctx *context.Context, form auth.CreateCloudBra
return
}

bootFileExist, err := ctx.Repo.FileExists(bootFile, branchName)
if err != nil || !bootFileExist {
log.Error("Get bootfile error:", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_bootfile_err"), tpl, &form)
return
}

count, err := models.GetCloudbrainCountByUserID(ctx.User.ID, jobType)
if err != nil {
log.Error("GetCloudbrainCountByUserID failed:%v", err, ctx.Data["MsgID"])
@@ -1228,6 +1245,15 @@ func StopJobsByRepoID(repoID int64) {
StopJobs(cloudBrains)
}

func DeleteJobsByRepoID(repoID int64) {
cloudBrains, err := models.GetCloudbrainsNeededDeleteByRepoID(repoID)
if err != nil {
log.Warn("Failed to get cloudBrain info", err)
return
}
DeleteJobs(cloudBrains)
}

/**

*/
@@ -1263,6 +1289,36 @@ func StopJobs(cloudBrains []*models.Cloudbrain) {
}
}

func DeleteJobs(cloudBrains []*models.Cloudbrain) {
for _, taskInfo := range cloudBrains {
err := models.DeleteJob(taskInfo)
if err != nil {
log.Warn("Failed to DeleteJob:", err)
return
}
if taskInfo.Type == models.TypeCloudBrainOne {
cloudbrain.DelCloudBrainJob(taskInfo.JobName)
DeleteCloudbrainJobStorage(taskInfo.JobName, models.TypeCloudBrainOne)
}
if taskInfo.Type == models.TypeCloudBrainTwo {
if taskInfo.JobType == string(models.JobTypeTrain) || taskInfo.JobType == string(models.JobTypeInference) {

modelarts.DelTrainJob(taskInfo.JobID)
DeleteJobStorage(taskInfo.JobName)
}
if taskInfo.JobType == string(models.JobTypeDebug) {
modelarts.DelNotebook2(taskInfo.JobID)
}
}
if taskInfo.Type == models.TypeC2Net {
if taskInfo.JobType == string(models.JobTypeTrain) {
cloudbrain.DelCloudBrainJob(taskInfo.JobName)
DeleteCloudbrainJobStorage(taskInfo.JobName, models.TypeCloudBrainOne)
}
}
}
}

func retry(attempts int, sleep time.Duration, f func() error) (err error) {
for i := 0; i < attempts; i++ {
if i > 0 {
@@ -1330,7 +1386,7 @@ func deleteCloudbrainJob(ctx *context.Context) error {
return err
}

deleteJobStorage(task.JobName, models.TypeCloudBrainOne)
DeleteCloudbrainJobStorage(task.JobName, models.TypeCloudBrainOne)

return nil
}
@@ -1717,7 +1773,7 @@ func mkPathAndReadMeFile(path string, text string) error {
return nil
}

func deleteJobStorage(jobName string, cloudbrainType int) error {
func DeleteCloudbrainJobStorage(jobName string, cloudbrainType int) error {
//delete local
localJobPath := setting.JobPath + jobName
err := os.RemoveAll(localJobPath)
@@ -1811,70 +1867,24 @@ func SyncCloudbrainStatus() {
}
} else if task.Type == models.TypeCloudBrainTwo {
if task.JobType == string(models.JobTypeDebug) {
//result, err := modelarts.GetJob(task.JobID)
result, err := modelarts.GetNotebook2(task.JobID)
err := modelarts.HandleNotebookInfo(task)
if err != nil {
log.Error("GetJob(%s) failed:%v", task.JobName, err)
log.Error("HandleNotebookInfo(%s) failed:%v", task.DisplayJobName, err)
continue
}

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)
}
err = models.UpdateJob(task)
if err != nil {
log.Error("UpdateJob(%s) failed:%v", task.JobName, err)
continue
}
}
} else if task.JobType == string(models.JobTypeTrain) || task.JobType == string(models.JobTypeInference) {
result, err := modelarts.GetTrainJob(task.JobID, strconv.FormatInt(task.VersionID, 10))
err := modelarts.HandleTrainJobInfo(task)
if err != nil {
log.Error("GetTrainJob(%s) failed:%v", task.JobName, err)
log.Error("HandleTrainJobInfo(%s) failed:%v", task.DisplayJobName, err)
continue
}

if result != nil {
oldStatus := task.Status
task.Status = modelarts.TransTrainJobStatus(result.IntStatus)
task.Duration = result.Duration / 1000
task.TrainJobDuration = result.TrainJobDuration

if task.StartTime == 0 && result.StartTime > 0 {
task.StartTime = timeutil.TimeStamp(result.StartTime / 1000)
}
task.TrainJobDuration = models.ConvertDurationToStr(task.Duration)
if task.EndTime == 0 && models.IsTrainJobTerminal(task.Status) && task.StartTime > 0 {
task.EndTime = task.StartTime.Add(task.Duration)
}
task.CorrectCreateUnix()
if oldStatus != task.Status {
notification.NotifyChangeCloudbrainStatus(task, oldStatus)
}
err = models.UpdateJob(task)
if err != nil {
log.Error("UpdateJob(%s) failed:%v", task.JobName, err)
continue
}
}
} else {
log.Error("task.JobType(%s) is error:%s", task.JobName, task.JobType)
log.Error("task.JobType(%s) is error:%s", task.DisplayJobName, task.JobType)
}
} else if task.Type == models.TypeC2Net {
result, err := grampus.GetJob(task.JobID)
if err != nil {
log.Error("GetTrainJob(%s) failed:%v", task.JobName, err)
log.Error("GetTrainJob(%s) failed:%v", task.DisplayJobName, err)
continue
}

@@ -2708,7 +2718,7 @@ func getTrainJobCommand(form auth.CreateCloudBrainForm) (string, error) {
}
}

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

return command, nil
}


+ 115
- 11
routers/repo/dataset.go View File

@@ -9,6 +9,8 @@ import (
"strings"
"unicode/utf8"

"code.gitea.io/gitea/services/repository"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/auth"
"code.gitea.io/gitea/modules/base"
@@ -22,6 +24,7 @@ const (
tplDatasetCreate base.TplName = "repo/datasets/create"
tplDatasetEdit base.TplName = "repo/datasets/edit"
taskstplIndex base.TplName = "repo/datasets/tasks/index"
tplReference base.TplName = "repo/datasets/reference"
)

// MustEnableDataset check if repository enable internal dataset
@@ -266,6 +269,37 @@ func CreateDatasetPost(ctx *context.Context, form auth.CreateDatasetForm) {
ctx.JSON(http.StatusOK, models.BaseOKMessage)
}

}
func ReferenceDatasetDelete(ctx *context.Context) {
repoID := ctx.Repo.Repository.ID
datasetId, _ := strconv.ParseInt(ctx.Params(":id"), 10, 64)

oldDatasetIds := models.GetDatasetIdsByRepoID(repoID)

var newDatasetIds []int64

for _, tempDatasetId := range oldDatasetIds {
if datasetId != tempDatasetId {
newDatasetIds = append(newDatasetIds, tempDatasetId)
}
}
err := models.NewDatasetIdsByRepoID(repoID, newDatasetIds)
if err != nil {
ctx.JSON(http.StatusOK, models.BaseErrorMessage("dataset.cancel_reference_dataset_fail"))
}
ctx.JSON(http.StatusOK, models.BaseOKMessage)

}

func ReferenceDatasetPost(ctx *context.Context, form auth.ReferenceDatasetForm) {
repoID := ctx.Repo.Repository.ID
err := models.NewDatasetIdsByRepoID(repoID, form.DatasetID)
if err != nil {
ctx.JSON(http.StatusOK, models.BaseErrorMessage("dataset.reference_dataset_fail"))
}

ctx.JSON(http.StatusOK, models.BaseOKMessage)

}

func EditDatasetPost(ctx *context.Context, form auth.EditDatasetForm) {
@@ -412,18 +446,17 @@ func MyDatasets(ctx *context.Context) {

func datasetMultiple(ctx *context.Context, opts *models.SearchDatasetOptions) {
page := ctx.QueryInt("page")
cloudbrainType := ctx.QueryInt("type")
keyword := strings.Trim(ctx.Query("q"), " ")
orderBy := models.SearchOrderByRecentUpdated
opts.Keyword = keyword
opts.SearchOrderBy = orderBy
if opts.SearchOrderBy.String() == "" {
opts.SearchOrderBy = models.SearchOrderByRecentUpdated
}

opts.RecommendOnly = ctx.QueryBool("recommend")
opts.CloudBrainType = cloudbrainType
opts.ListOptions = models.ListOptions{
Page: page,
PageSize: setting.UI.DatasetPagingNum,
}
opts.NeedAttachment = true
opts.JustNeedZipFile = true
opts.User = ctx.User

@@ -449,22 +482,52 @@ func datasetMultiple(ctx *context.Context, opts *models.SearchDatasetOptions) {
"data": string(data),
"count": strconv.FormatInt(count, 10),
})

}

func CurrentRepoDatasetMultiple(ctx *context.Context) {

datasetIds := models.GetDatasetIdsByRepoID(ctx.Repo.Repository.ID)
searchOrderBy := getSearchOrderByInValues(datasetIds)
opts := &models.SearchDatasetOptions{
RepoID: ctx.Repo.Repository.ID,
RepoID: ctx.Repo.Repository.ID,
NeedAttachment: true,
CloudBrainType: ctx.QueryInt("type"),
DatasetIDs: datasetIds,
SearchOrderBy: searchOrderBy,
}

datasetMultiple(ctx, opts)

}

func getSearchOrderByInValues(datasetIds []int64) models.SearchOrderBy {
if len(datasetIds) == 0 {
return ""
}
searchOrderBy := "CASE id "
for i, id := range datasetIds {
searchOrderBy += fmt.Sprintf(" WHEN %d THEN %d", id, i+1)
}
searchOrderBy += " ELSE 0 END"
return models.SearchOrderBy(searchOrderBy)
}

func MyDatasetsMultiple(ctx *context.Context) {

opts := &models.SearchDatasetOptions{
UploadAttachmentByMe: true,
NeedAttachment: true,
CloudBrainType: ctx.QueryInt("type"),
}
datasetMultiple(ctx, opts)

}

func ReferenceDatasetAvailable(ctx *context.Context) {

opts := &models.SearchDatasetOptions{
PublicOnly: true,
NeedAttachment: false,
CloudBrainType: models.TypeCloudBrainAll,
}
datasetMultiple(ctx, opts)

@@ -473,7 +536,9 @@ func MyDatasetsMultiple(ctx *context.Context) {
func PublicDatasetMultiple(ctx *context.Context) {

opts := &models.SearchDatasetOptions{
PublicOnly: true,
PublicOnly: true,
NeedAttachment: true,
CloudBrainType: ctx.QueryInt("type"),
}
datasetMultiple(ctx, opts)

@@ -482,11 +547,50 @@ func PublicDatasetMultiple(ctx *context.Context) {
func MyFavoriteDatasetMultiple(ctx *context.Context) {

opts := &models.SearchDatasetOptions{
StarByMe: true,
DatasetIDs: models.GetDatasetIdsStarByUser(ctx.User.ID),
StarByMe: true,
DatasetIDs: models.GetDatasetIdsStarByUser(ctx.User.ID),
NeedAttachment: true,
CloudBrainType: ctx.QueryInt("type"),
}
datasetMultiple(ctx, opts)
}
func ReferenceDataset(ctx *context.Context) {
MustEnableDataset(ctx)
ctx.Data["PageIsDataset"] = true
ctx.Data["MaxReferenceDatasetNum"] = setting.RepoMaxReferenceDatasetNum
ctx.Data["CanWrite"] = ctx.Repo.CanWrite(models.UnitTypeDatasets)
ctx.HTML(200, tplReference)

}

func ReferenceDatasetData(ctx *context.Context) {
MustEnableDataset(ctx)
datasetIds := models.GetDatasetIdsByRepoID(ctx.Repo.Repository.ID)
var datasets models.DatasetList
var err error
if len(datasetIds) > 0 {

opts := &models.SearchDatasetOptions{
DatasetIDs: datasetIds,
NeedAttachment: false,
CloudBrainType: models.TypeCloudBrainAll,
ListOptions: models.ListOptions{
Page: 1,
PageSize: setting.RepoMaxReferenceDatasetNum,
},
SearchOrderBy: getSearchOrderByInValues(datasetIds),
QueryReference: true,
}
datasets, _, err = models.SearchDataset(opts)
if err != nil {
ctx.ServerError("SearchDatasets", err)
return
}
}

ctx.JSON(http.StatusOK, repository.ConvertToDatasetWithStar(ctx, datasets))

}

func PublicDataset(ctx *context.Context) {
page := ctx.QueryInt("page")


+ 40
- 20
routers/repo/grampus.go View File

@@ -215,6 +215,14 @@ func GrampusTrainJobGpuCreate(ctx *context.Context, form auth.CreateGrampusTrain
return
}

bootFileExist, err := ctx.Repo.FileExists(bootFile, branchName)
if err != nil || !bootFileExist {
log.Error("Get bootfile error:", err, ctx.Data["MsgID"])
grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU)
ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_bootfile_err"), tplGrampusTrainJobGPUNew, &form)
return
}

errStr := checkSpecialPool(ctx, "GPU")
if errStr != "" {
grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU)
@@ -340,7 +348,7 @@ func GrampusTrainJobGpuCreate(ctx *context.Context, form auth.CreateGrampusTrain
EngineName: image,
DatasetName: attachment.Name,
IsLatestVersion: modelarts.IsLatestVersion,
VersionCount: modelarts.VersionCount,
VersionCount: modelarts.VersionCountOne,
WorkServerNumber: 1,
}

@@ -390,7 +398,7 @@ func GrampusTrainJobNpuCreate(ctx *context.Context, form auth.CreateGrampusTrain
branchName := form.BranchName
isLatestVersion := modelarts.IsLatestVersion
flavorName := form.FlavorName
versionCount := modelarts.VersionCount
versionCount := modelarts.VersionCountOne
engineName := form.EngineName

if !jobNamePattern.MatchString(displayJobName) {
@@ -399,6 +407,14 @@ func GrampusTrainJobNpuCreate(ctx *context.Context, form auth.CreateGrampusTrain
return
}

bootFileExist, err := ctx.Repo.FileExists(bootFile, branchName)
if err != nil || !bootFileExist {
log.Error("Get bootfile error:", err, ctx.Data["MsgID"])
grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU)
ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_bootfile_err"), tplGrampusTrainJobNPUNew, &form)
return
}

errStr := checkSpecialPool(ctx, "NPU")
if errStr != "" {
grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU)
@@ -621,7 +637,7 @@ func deleteGrampusJob(ctx *context.Context) error {
if task.ComputeResource == models.NPUResource {
storageType = models.TypeCloudBrainTwo
}
deleteJobStorage(task.JobName, storageType)
DeleteCloudbrainJobStorage(task.JobName, storageType)

return nil
}
@@ -751,10 +767,6 @@ func generateCommand(repoName, processorType, codeRemotePath, dataRemotePath, bo
command += commandDownload
}

//check download result
commandCheckRes := "bash -c \"[[ $? -eq 0 ]] && exit 0 || exit -1;\";"
command += commandCheckRes

//unzip code & dataset
toolUnzip := "unzip -q '"
if strings.HasSuffix(datasetName, ".tar.gz") {
@@ -763,16 +775,22 @@ func generateCommand(repoName, processorType, codeRemotePath, dataRemotePath, bo
commandUnzip := "cd " + workDir + "code;unzip -q master.zip;echo \"start to unzip dataset\";cd " + workDir + "dataset;" + toolUnzip + datasetName + "';"
command += commandUnzip

//check unzip result
commandCheckRes = "bash -c \"[[ $? -eq 0 ]] && exit 0 || exit -1;\";"
command += commandCheckRes

command += "echo \"unzip finished;start to exec code;\";"

// set export
var commandExport string
if processorType == grampus.ProcessorTypeNPU {
commandExport = "export bucket=" + setting.Bucket + " && export remote_path=" + outputRemotePath + ";"
} else if processorType == grampus.ProcessorTypeGPU {
commandExport = "export env=" + setting.Grampus.Env + " && export remote_path=" + outputRemotePath + ";"
}

command += commandExport

//exec code
var parameters models.Parameters
var paramCode string
param := make([]models.Parameter, 0)
if len(paramSrc) != 0 {
err := json.Unmarshal([]byte(paramSrc), &parameters)
if err != nil {
@@ -781,15 +799,17 @@ func generateCommand(repoName, processorType, codeRemotePath, dataRemotePath, bo
}

for _, parameter := range parameters.Parameter {
param = append(param, models.Parameter{
Label: parameter.Label,
Value: parameter.Value,
})
paramCode += " --" + parameter.Label + "=" + parameter.Value
}
}

commandCode := "cd " + workDir + "code/" + strings.ToLower(repoName) + ";python " + bootFile + paramCode + ";"
var commandCode string
if processorType == grampus.ProcessorTypeNPU {
commandCode = "/bin/bash /home/work/run_train_for_openi.sh " + workDir + "code/" + strings.ToLower(repoName) + "/" + bootFile + " /tmp/log/train.log" + paramCode + ";"
} else if processorType == grampus.ProcessorTypeGPU {
commandCode = "cd " + workDir + "code/" + strings.ToLower(repoName) + ";python " + bootFile + paramCode + ";"
}

command += commandCode

//get exec result
@@ -798,15 +818,15 @@ func generateCommand(repoName, processorType, codeRemotePath, dataRemotePath, bo

//upload models
if processorType == grampus.ProcessorTypeNPU {
commandUpload := "cd " + workDir + "script_for_grampus/;./uploader_for_obs " + setting.Bucket + " " + outputRemotePath + " " + workDir + "output/;"
commandUpload := "cd " + workDir + "script_for_grampus/;./uploader_for_npu " + setting.Bucket + " " + outputRemotePath + " " + workDir + "output/;"
command += commandUpload
} else if processorType == grampus.ProcessorTypeGPU {
commandUpload := "cd " + workDir + "script_for_grampus/;./uploader_for_minio " + setting.Grampus.Env + " " + outputRemotePath + " " + workDir + "output/;"
commandUpload := "cd " + workDir + "script_for_grampus/;./uploader_for_gpu " + setting.Grampus.Env + " " + outputRemotePath + " " + workDir + "output/;"
command += commandUpload
}

//check exec result
commandCheckRes = "bash -c \"[[ $result -eq 0 ]] && exit 0 || exit -1\""
commandCheckRes := "bash -c \"[[ $result -eq 0 ]] && exit 0 || exit -1\""
command += commandCheckRes

return command, nil


+ 227
- 220
routers/repo/modelarts.go View File

@@ -15,9 +15,6 @@ import (
"time"
"unicode/utf8"

"code.gitea.io/gitea/modules/notification"
"code.gitea.io/gitea/modules/timeutil"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/auth"
"code.gitea.io/gitea/modules/base"
@@ -26,9 +23,11 @@ import (
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/modelarts"
"code.gitea.io/gitea/modules/notification"
"code.gitea.io/gitea/modules/obs"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/storage"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
)

@@ -272,33 +271,15 @@ func NotebookShow(ctx *context.Context) {
return
}

result, err := modelarts.GetNotebook2(task.JobID)
if err != nil {
log.Error("GET job error", err.Error())
ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
return
}

if result != nil {
if task.DeletedAt.IsZero() { //normal record
if task.Status != result.Status {
oldStatus := task.Status
task.Status = result.Status
models.ParseAndSetDurationFromModelArtsNotebook(result, task)
notification.NotifyChangeCloudbrainStatus(task, oldStatus)
err = models.UpdateJob(task)
if err != nil {
log.Error("GET job error", err.Error())
ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
return
}
}
} else { //deleted record

}
if task.FlavorCode == "" {
task.FlavorCode = result.Flavor
if task.DeletedAt.IsZero() { //normal record
err := modelarts.HandleNotebookInfo(task)
if err != nil {
ctx.Data["error"] = err.Error()
ctx.RenderWithErr(err.Error(), tplModelArtsNotebookShow, nil)
return
}
} else { //deleted record

}

datasetDownload := make([]models.DatasetDownload, 0)
@@ -435,82 +416,129 @@ func NotebookDebug2(ctx *context.Context) {
ctx.Redirect(result.Url + "?token=" + result.Token)
}

func NotebookManage(ctx *context.Context) {
var ID = ctx.Params(":id")
var action = ctx.Params(":action")
var resultCode = "0"
func NotebookRestart(ctx *context.Context) {
var id = ctx.Params(":id")
var resultCode = "-1"
var errorMsg = ""
var status = ""

task := ctx.Cloudbrain

for {
task, err := models.GetCloudbrainByID(ID)
if err != nil {
log.Error("get task(%s) failed:%v", task.JobName, err.Error(), ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "system error"
ctx.CheckWechatBind()
if ctx.Written() {
return
}
if task.Status != string(models.ModelArtsStopped) && task.Status != string(models.ModelArtsStartFailed) && task.Status != string(models.ModelArtsCreateFailed) {
log.Error("the job(%s) is not stopped", task.JobName, ctx.Data["MsgID"])
errorMsg = "the job is not stopped"
break
}

if action == models.ActionStop {
if task.Status != string(models.ModelArtsRunning) {
log.Error("the job(%s) is not running", task.JobName, ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "the job is not running"
break
}

if !ctx.IsSigned || (ctx.User.ID != task.UserID && !ctx.IsUserSiteAdmin() && !ctx.IsUserRepoOwner()) {
log.Error("the user has no right ro stop the job", task.JobName, ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "you have no right to stop the job"
break
}
} else if action == models.ActionRestart {
ctx.CheckWechatBind()
if ctx.Written() {
return
}
if task.Status != string(models.ModelArtsStopped) && task.Status != string(models.ModelArtsStartFailed) && task.Status != string(models.ModelArtsCreateFailed) {
log.Error("the job(%s) is not stopped", task.JobName, ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "the job is not stopped"
count, err := models.GetCloudbrainNotebookCountByUserID(ctx.User.ID)
if err != nil {
log.Error("GetCloudbrainNotebookCountByUserID failed:%v", err, ctx.Data["MsgID"])
errorMsg = "system error"
break
} else {
if count >= 1 {
log.Error("the user already has running or waiting task", ctx.Data["MsgID"])
errorMsg = "you have already a running or waiting task, can not create more"
break
}
}

if !ctx.IsSigned || (ctx.User.ID != task.UserID && !ctx.IsUserSiteAdmin()) {
log.Error("the user has no right ro restart the job", task.JobName, ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "you have no right to restart the job"
break
}
createTime := timeutil.TimeStampNow()
param := models.NotebookAction{
Action: models.ActionStart,
}

count, err := models.GetCloudbrainNotebookCountByUserID(ctx.User.ID)
if err != nil {
log.Error("GetCloudbrainNotebookCountByUserID failed:%v", err, ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "system error"
break
} else {
if count >= 1 {
log.Error("the user already has running or waiting task", ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "you have already a running or waiting task, can not create more"
break
res, err := modelarts.ManageNotebook2(task.JobID, param)
if err != nil {
log.Error("ManageNotebook2(%s) failed:%v", task.DisplayJobName, err.Error(), ctx.Data["MsgID"])
/* 暂不处理再次调试502的场景,详情见方案
if strings.HasPrefix(err.Error(), modelarts.UnknownErrorPrefix) {
log.Info("(%s)unknown error, set temp status", task.DisplayJobName)
errTemp := models.InsertCloudbrainTemp(&models.CloudbrainTemp{
JobID: task.JobID,
VersionID: models.TempVersionId,
Status: models.TempJobStatus,
Type: task.Type,
JobName: task.JobName,
JobType: task.JobType,
})
if errTemp != nil {
log.Error("InsertCloudbrainTemp failed: %v", errTemp.Error())
}
}
*/
errorMsg = err.Error()
break
}

action = models.ActionStart
} else {
log.Error("the action(%s) is illegal", action, ctx.Data["MsgID"])
newTask := &models.Cloudbrain{
Status: res.Status,
UserID: task.UserID,
RepoID: task.RepoID,
JobID: task.JobID,
JobName: task.JobName,
DisplayJobName: task.DisplayJobName,
JobType: task.JobType,
Type: task.Type,
Uuid: task.Uuid,
Image: task.Image,
ComputeResource: task.ComputeResource,
Description: task.Description,
CreatedUnix: createTime,
UpdatedUnix: createTime,
FlavorCode: task.FlavorCode,
FlavorName: task.FlavorName,
}

err = models.RestartCloudbrain(task, newTask)
if err != nil {
log.Error("RestartCloudbrain(%s) failed:%v", task.JobName, err.Error(), ctx.Data["MsgID"])
errorMsg = "system error"
break
}

id = strconv.FormatInt(newTask.ID, 10)

status = res.Status
resultCode = "0"
notification.NotifyOtherTask(ctx.User, ctx.Repo.Repository, id, newTask.DisplayJobName, models.ActionCreateDebugNPUTask)

break
}

ctx.JSON(200, map[string]string{
"result_code": resultCode,
"error_msg": errorMsg,
"status": status,
"id": id,
})
}

func NotebookStop(ctx *context.Context) {
var id = ctx.Params(":id")
var resultCode = "0"
var errorMsg = ""
var status = ""

task := ctx.Cloudbrain

for {
if task.Status != string(models.ModelArtsRunning) {
log.Error("the job(%s) is not running", task.JobName, ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "非法操作"
errorMsg = "the job is not running"
break
}

param := models.NotebookAction{
Action: action,
Action: models.ActionStop,
}
createTime := timeutil.TimeStampNow()
res, err := modelarts.ManageNotebook2(task.JobID, param)
if err != nil {
log.Error("ManageNotebook2(%s) failed:%v", task.JobName, err.Error(), ctx.Data["MsgID"])
@@ -523,52 +551,21 @@ func NotebookManage(ctx *context.Context) {
}

status = res.Status
if action == models.ActionStart {
newTask := &models.Cloudbrain{
Status: status,
UserID: task.UserID,
RepoID: task.RepoID,
JobID: task.JobID,
JobName: task.JobName,
DisplayJobName: task.DisplayJobName,
JobType: task.JobType,
Type: task.Type,
Uuid: task.Uuid,
Image: task.Image,
ComputeResource: task.ComputeResource,
Description: task.Description,
CreatedUnix: createTime,
UpdatedUnix: createTime,
FlavorCode: task.FlavorCode,
FlavorName: task.FlavorName,
}

err = models.RestartCloudbrain(task, newTask)
if err != nil {
log.Error("RestartCloudbrain(%s) failed:%v", task.JobName, err.Error(), ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "system error"
break
}
ID = strconv.FormatInt(newTask.ID, 10)
notification.NotifyOtherTask(ctx.User, ctx.Repo.Repository, ID, task.DisplayJobName, models.ActionCreateDebugNPUTask)
} else {
oldStatus := task.Status
task.Status = res.Status
if task.EndTime == 0 && models.IsModelArtsDebugJobTerminal(task.Status) {
task.EndTime = timeutil.TimeStampNow()
}
task.ComputeAndSetDuration()
if oldStatus != task.Status {
notification.NotifyChangeCloudbrainStatus(task, oldStatus)
}
err = models.UpdateJob(task)
if err != nil {
log.Error("UpdateJob(%s) failed:%v", task.JobName, err.Error(), ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "system error"
break
}
oldStatus := task.Status
task.Status = res.Status
if task.EndTime == 0 && models.IsModelArtsDebugJobTerminal(task.Status) {
task.EndTime = timeutil.TimeStampNow()
}
task.ComputeAndSetDuration()
if oldStatus != task.Status {
notification.NotifyChangeCloudbrainStatus(task, oldStatus)
}
err = models.UpdateJob(task)
if err != nil {
log.Error("UpdateJob(%s) failed:%v", task.JobName, err.Error(), ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "system error"
break
}

break
@@ -578,7 +575,7 @@ func NotebookManage(ctx *context.Context) {
"result_code": resultCode,
"error_msg": errorMsg,
"status": status,
"id": ID,
"id": id,
})
}

@@ -901,12 +898,12 @@ func trainJobNewVersionDataPrepare(ctx *context.Context) error {
ctx.Data["display_job_name"] = task.DisplayJobName
ctx.Data["job_name"] = task.JobName

attachs, err := models.GetModelArtsTrainAttachments(ctx.User.ID)
if err != nil {
ctx.ServerError("GetAllUserAttachments failed:", err)
return err
}
ctx.Data["attachments"] = attachs
// attachs, err := models.GetModelArtsTrainAttachments(ctx.User.ID)
// if err != nil {
// ctx.ServerError("GetAllUserAttachments failed:", err)
// return err
// }
// ctx.Data["attachments"] = attachs

var resourcePools modelarts.ResourcePool
if err = json.Unmarshal([]byte(setting.ResourcePools), &resourcePools); err != nil {
@@ -950,12 +947,16 @@ func trainJobNewVersionDataPrepare(ctx *context.Context) error {
ctx.ServerError("GetBranches error:", err)
return err
}

_, _, datasetNames, _, err := getDatasUrlListByUUIDS(task.Uuid)
if err != nil {
ctx.ServerError("GetAllUserAttachments failed:", err)
return err
}
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"] = task.DatasetName
ctx.Data["dataset_name"] = datasetNames
ctx.Data["work_server_number"] = task.WorkServerNumber
ctx.Data["flavor_name"] = task.FlavorName
ctx.Data["engine_name"] = task.EngineName
@@ -1089,10 +1090,10 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm)
outputObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.OutputPath + VersionOutputPath + "/"
logObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.LogPath + VersionOutputPath + "/"
// dataPath := "/" + setting.Bucket + "/" + setting.BasePath + path.Join(uuid[0:1], uuid[1:2]) + "/" + uuid + uuid + "/"
branch_name := form.BranchName
branchName := form.BranchName
isLatestVersion := modelarts.IsLatestVersion
FlavorName := form.FlavorName
VersionCount := modelarts.VersionCount
VersionCount := modelarts.VersionCountOne
EngineName := form.EngineName

count, err := models.GetCloudbrainTrainJobCountByUserID(ctx.User.ID)
@@ -1117,6 +1118,14 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm)
return
}

bootFileExist, err := ctx.Repo.FileExists(bootFile, branchName)
if err != nil || !bootFileExist {
log.Error("Get bootfile error:", err)
trainJobErrorNewDataPrepare(ctx, form)
ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_bootfile_err"), tplModelArtsTrainJobNew, &form)
return
}

errStr := checkModelArtsSpecialPool(ctx, flavorCode, string(models.JobTypeTrain))
if errStr != "" {
trainJobErrorNewDataPrepare(ctx, form)
@@ -1148,9 +1157,9 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm)
}

gitRepo, _ := git.OpenRepository(repo.RepoPath())
commitID, _ := gitRepo.GetBranchCommitID(branch_name)
commitID, _ := gitRepo.GetBranchCommitID(branchName)

if err := downloadCode(repo, codeLocalPath, branch_name); err != nil {
if err := downloadCode(repo, codeLocalPath, branchName); err != nil {
log.Error("downloadCode failed, server timed out: %s (%v)", repo.FullName(), err)
trainJobErrorNewDataPrepare(ctx, form)
ctx.RenderWithErr(ctx.Tr("cloudbrain.load_code_failed"), tplModelArtsTrainJobNew, &form)
@@ -1292,7 +1301,7 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm)
Parameters: param,
CommitID: commitID,
IsLatestVersion: isLatestVersion,
BranchName: branch_name,
BranchName: branchName,
Params: form.Params,
FlavorName: FlavorName,
EngineName: EngineName,
@@ -1394,7 +1403,7 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ
outputObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.OutputPath + VersionOutputPath + "/"
logObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.LogPath + VersionOutputPath + "/"
// dataPath := "/" + setting.Bucket + "/" + setting.BasePath + path.Join(uuid[0:1], uuid[1:2]) + "/" + uuid + uuid + "/"
branch_name := form.BranchName
branchName := form.BranchName
PreVersionName := form.VersionName
FlavorName := form.FlavorName
EngineName := form.EngineName
@@ -1414,6 +1423,14 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ
return
}

bootFileExist, err := ctx.Repo.FileExists(bootFile, branchName)
if err != nil || !bootFileExist {
log.Error("Get bootfile error:", err)
versionErrorDataPrepare(ctx, form)
ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_bootfile_err"), tplModelArtsTrainJobVersionNew, &form)
return
}

errStr := checkModelArtsSpecialPool(ctx, flavorCode, string(models.JobTypeTrain))
if errStr != "" {
versionErrorDataPrepare(ctx, form)
@@ -1428,8 +1445,8 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ
}

gitRepo, _ := git.OpenRepository(repo.RepoPath())
commitID, _ := gitRepo.GetBranchCommitID(branch_name)
if err := downloadCode(repo, codeLocalPath, branch_name); err != nil {
commitID, _ := gitRepo.GetBranchCommitID(branchName)
if err := downloadCode(repo, codeLocalPath, branchName); err != nil {
log.Error("Failed git clone repo to local(!: %s (%v)", repo.FullName(), err)
versionErrorDataPrepare(ctx, form)
ctx.RenderWithErr(ctx.Tr("cloudbrain.load_code_failed"), tplModelArtsTrainJobVersionNew, &form)
@@ -1582,7 +1599,7 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ
Parameters: param,
PreVersionId: task.VersionID,
CommitID: commitID,
BranchName: branch_name,
BranchName: branchName,
FlavorName: FlavorName,
EngineName: EngineName,
PreVersionName: PreVersionName,
@@ -1810,60 +1827,6 @@ func TrainJobShow(ctx *context.Context) {
ctx.HTML(http.StatusOK, tplModelArtsTrainJobShow)
}

func TrainJobGetLog(ctx *context.Context) {
ctx.Data["PageIsTrainJob"] = true

var jobID = ctx.Params(":jobid")
var logFileName = ctx.Query("file_name")
var baseLine = ctx.Query("base_line")
var order = ctx.Query("order")

if order != modelarts.OrderDesc && order != modelarts.OrderAsc {
log.Error("order(%s) check failed", order)
ctx.HTML(http.StatusBadRequest, tplModelArtsTrainJobShow)
return
}

task, err := models.GetCloudbrainByJobID(jobID)
if err != nil {
log.Error("GetCloudbrainByJobID(%s) failed:%v", jobID, err.Error())
ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobShow, nil)
return
}

result, err := modelarts.GetTrainJobLog(jobID, strconv.FormatInt(task.VersionID, 10), baseLine, logFileName, order, modelarts.Lines)
if err != nil {
log.Error("GetTrainJobLog(%s) failed:%v", jobID, err.Error())
ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobShow, nil)
return
}

ctx.Data["log"] = result
//ctx.HTML(http.StatusOK, tplModelArtsTrainJobShow)
}

func trainJobGetLog(jobID string) (*models.GetTrainJobLogFileNamesResult, *models.GetTrainJobLogResult, error) {
task, err := models.GetCloudbrainByJobID(jobID)
if err != nil {
log.Error("GetCloudbrainByJobID(%s) failed:%v", jobID, err.Error())
return nil, nil, err
}

resultLogFile, err := modelarts.GetTrainJobLogFileNames(jobID, strconv.FormatInt(task.VersionID, 10))
if err != nil {
log.Error("GetTrainJobLogFileNames(%s) failed:%v", jobID, err.Error())
return nil, nil, err
}

result, err := modelarts.GetTrainJobLog(jobID, strconv.FormatInt(task.VersionID, 10), "", resultLogFile.LogFileList[0], modelarts.OrderDesc, modelarts.Lines)
if err != nil {
log.Error("GetTrainJobLog(%s) failed:%v", jobID, err.Error())
return nil, nil, err
}

return resultLogFile, result, err
}

func TrainJobDel(ctx *context.Context) {
var jobID = ctx.Params(":jobid")
var listType = ctx.Query("listType")
@@ -1882,6 +1845,16 @@ func TrainJobDel(ctx *context.Context) {
return
}

for _, task := range VersionListTasks {
if task.Status != string(models.ModelArtsTrainJobImageFailed) && task.Status != string(models.ModelArtsTrainJobSubmitFailed) && task.Status != string(models.ModelArtsTrainJobDeleteFailed) &&
task.Status != string(models.ModelArtsTrainJobCompleted) && task.Status != string(models.ModelArtsTrainJobFailed) &&
task.Status != string(models.ModelArtsTrainJobKilled) && task.Status != string(models.ModelArtsTrainJobCanceled) && task.Status != string(models.ModelArtsTrainJobLost) {
log.Error("the job(%s) version has not been stopped", task.JobName)
ctx.RenderWithErr("the job version has not been stopped", tplModelArtsTrainJobIndex, nil)
return
}
}

//删除modelarts上的任务记录
_, err = modelarts.DelTrainJob(jobID)
if err != nil {
@@ -1930,15 +1903,6 @@ func TrainJobStop(ctx *context.Context) {
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/train-job?listType=" + listType)
}

func canUserCreateTrainJob(uid int64) (bool, error) {
org, err := models.GetOrgByName(setting.AllowedOrg)
if err != nil {
log.Error("get allowed org failed: ", setting.AllowedOrg)
return false, err
}

return org.IsOrgMember(uid)
}
func canUserCreateTrainJobVersion(ctx *context.Context, userID int64) (bool, error) {
if ctx == nil || ctx.User == nil {
log.Error("user unlogin!")
@@ -2024,13 +1988,13 @@ func InferenceJobCreate(ctx *context.Context, form auth.CreateModelArtsInference
codeObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.CodePath
resultObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.ResultPath + VersionOutputPath + "/"
logObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.LogPath + VersionOutputPath + "/"
dataPath := "/" + setting.Bucket + "/" + setting.BasePath + path.Join(uuid[0:1], uuid[1:2]) + "/" + uuid + uuid + "/"
branch_name := form.BranchName
//dataPath := "/" + setting.Bucket + "/" + setting.BasePath + path.Join(uuid[0:1], uuid[1:2]) + "/" + uuid + uuid + "/"
branchName := form.BranchName
FlavorName := form.FlavorName
EngineName := form.EngineName
LabelName := form.LabelName
isLatestVersion := modelarts.IsLatestVersion
VersionCount := modelarts.VersionCount
VersionCount := modelarts.VersionCountOne
trainUrl := form.TrainUrl
modelName := form.ModelName
modelVersion := form.ModelVersion
@@ -2060,6 +2024,14 @@ func InferenceJobCreate(ctx *context.Context, form auth.CreateModelArtsInference
return
}

bootFileExist, err := ctx.Repo.FileExists(bootFile, branchName)
if err != nil || !bootFileExist {
log.Error("Get bootfile error:", err)
inferenceJobErrorNewDataPrepare(ctx, form)
ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_bootfile_err"), tplModelArtsInferenceJobNew, &form)
return
}

//Determine whether the task name of the task in the project is duplicated
tasks, err := models.GetCloudbrainsByDisplayJobName(repo.ID, string(models.JobTypeInference), displayJobName)
if err == nil {
@@ -2092,9 +2064,9 @@ func InferenceJobCreate(ctx *context.Context, form auth.CreateModelArtsInference
}

gitRepo, _ := git.OpenRepository(repo.RepoPath())
commitID, _ := gitRepo.GetBranchCommitID(branch_name)
commitID, _ := gitRepo.GetBranchCommitID(branchName)

if err := downloadCode(repo, codeLocalPath, branch_name); err != nil {
if err := downloadCode(repo, codeLocalPath, branchName); err != nil {
log.Error("Create task failed, server timed out: %s (%v)", repo.FullName(), err)
inferenceJobErrorNewDataPrepare(ctx, form)
ctx.RenderWithErr(ctx.Tr("cloudbrain.load_code_failed"), tplModelArtsInferenceJobNew, &form)
@@ -2132,6 +2104,28 @@ func InferenceJobCreate(ctx *context.Context, form auth.CreateModelArtsInference
Label: modelarts.CkptUrl,
Value: "s3:/" + ckptUrl,
})

datasUrlList, dataUrl, datasetNames, isMultiDataset, err := getDatasUrlListByUUIDS(uuid)
if err != nil {
inferenceJobErrorNewDataPrepare(ctx, form)
ctx.RenderWithErr(ctx.Tr(errStr), tplModelArtsInferenceJobNew, &form)
return
}
dataPath := dataUrl
jsondatas, err := json.Marshal(datasUrlList)
if err != nil {
log.Error("Failed to Marshal: %v", err)
inferenceJobErrorNewDataPrepare(ctx, form)
ctx.RenderWithErr("json error:"+err.Error(), tplModelArtsInferenceJobNew, &form)
return
}
if isMultiDataset {
param = append(param, models.Parameter{
Label: modelarts.MultiDataUrl,
Value: string(jsondatas),
})
}

existDeviceTarget := false
if len(params) != 0 {
err := json.Unmarshal([]byte(params), &parameters)
@@ -2178,7 +2172,7 @@ func InferenceJobCreate(ctx *context.Context, form auth.CreateModelArtsInference
Uuid: uuid,
Parameters: param, //modelarts train parameters
CommitID: commitID,
BranchName: branch_name,
BranchName: branchName,
Params: form.Params,
FlavorName: FlavorName,
EngineName: EngineName,
@@ -2190,6 +2184,7 @@ func InferenceJobCreate(ctx *context.Context, form auth.CreateModelArtsInference
ModelVersion: modelVersion,
CkptName: ckptName,
ResultUrl: resultObsPath,
DatasetName: datasetNames,
}

err = modelarts.GenerateInferenceJob(ctx, req)
@@ -2744,11 +2739,23 @@ func getDatasUrlListByUUIDS(uuidStr string) ([]models.Datasurl, string, string,

datasetInfos := make(map[string]models.DatasetInfo)
attachs, err := models.GetAttachmentsByUUIDs(uuids)
if err != nil {
if err != nil || len(attachs) != len(uuids) {
log.Error("GetAttachmentsByUUIDs failed: %v", err)
return datasUrlList, dataUrl, datasetNames, isMultiDataset, errors.New("GetAttachmentsByUUIDs failed")
}
for i, attach := range attachs {

for i, tmpUuid := range uuids {
var attach *models.Attachment
for _, tmpAttach := range attachs {
if tmpAttach.UUID == tmpUuid {
attach = tmpAttach
break
}
}
if attach == nil {
log.Error("GetAttachmentsByUUIDs failed: %v", err)
return datasUrlList, dataUrl, datasetNames, isMultiDataset, errors.New("GetAttachmentsByUUIDs failed")
}
fileName := strings.TrimSuffix(strings.TrimSuffix(strings.TrimSuffix(attach.Name, ".zip"), ".tar.gz"), ".tgz")
for _, datasetInfo := range datasetInfos {
if fileName == datasetInfo.Name {


+ 12
- 1
routers/repo/setting.go View File

@@ -464,6 +464,16 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
}
return
}
dataset, err := models.GetDatasetByRepo(repo)
if err == nil {
if dataset != nil {
models.UpdateDatasetCreateUser(dataset.ID, newOwner)
} else {
log.Info("not found the dataset")
}
} else {
log.Info("error=" + err.Error())
}

log.Trace("Repository transferred: %s/%s -> %s", ctx.Repo.Owner.Name, repo.Name, newOwner)
ctx.Flash.Success(ctx.Tr("repo.settings.transfer_succeed"))
@@ -494,7 +504,8 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
return
}
log.Trace("Repository deleted: %s/%s", ctx.Repo.Owner.Name, repo.Name)
go StopJobsByRepoID(repo.ID)
// go StopJobsByRepoID(repo.ID)
go DeleteJobsByRepoID(repo.ID)

ctx.Flash.Success(ctx.Tr("repo.settings.deletion_success"))
ctx.Redirect(ctx.Repo.Owner.DashboardLink())


+ 12
- 2
routers/routes/routes.go View File

@@ -702,6 +702,9 @@ func RegisterRoutes(m *macaron.Macaron) {
reqRepoIssuesOrPullsReader := context.RequireRepoReaderOr(models.UnitTypeIssues, models.UnitTypePullRequests)
reqRepoDatasetReader := context.RequireRepoReader(models.UnitTypeDatasets)
reqRepoDatasetWriter := context.RequireRepoWriter(models.UnitTypeDatasets)
reqRepoDatasetReaderJson := context.RequireRepoReaderJson(models.UnitTypeDatasets)
reqRepoDatasetWriterJson := context.RequireRepoWriterJson(models.UnitTypeDatasets)

reqRepoCloudBrainReader := context.RequireRepoReader(models.UnitTypeCloudBrain)
reqRepoCloudBrainWriter := context.RequireRepoWriter(models.UnitTypeCloudBrain)
reqRepoModelManageReader := context.RequireRepoReader(models.UnitTypeModelManage)
@@ -1058,10 +1061,14 @@ func RegisterRoutes(m *macaron.Macaron) {

m.Group("/datasets", func() {
m.Get("", reqRepoDatasetReader, repo.DatasetIndex)
m.Get("/reference_datasets", reqRepoDatasetReader, repo.ReferenceDataset)
m.Get("/reference_datasets_data", reqRepoDatasetReaderJson, repo.ReferenceDatasetData)
m.Delete("/reference_datasets/:id", reqRepoDatasetWriterJson, repo.ReferenceDatasetDelete)
m.Put("/:id/:action", reqRepoDatasetReader, repo.DatasetAction)
m.Get("/create", reqRepoDatasetWriter, repo.CreateDataset)
m.Post("/create", reqRepoDatasetWriter, bindIgnErr(auth.CreateDatasetForm{}), repo.CreateDatasetPost)
m.Get("/edit/:id", reqRepoDatasetWriter, repo.EditDataset)
m.Post("/reference_datasets", reqRepoDatasetWriterJson, bindIgnErr(auth.ReferenceDatasetForm{}), repo.ReferenceDatasetPost)
m.Post("/edit", reqRepoDatasetWriter, bindIgnErr(auth.EditDatasetForm{}), repo.EditDatasetPost)
m.Get("/current_repo", repo.CurrentRepoDataset)
m.Get("/my_datasets", repo.MyDatasets)
@@ -1071,6 +1078,8 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Get("/current_repo_m", repo.CurrentRepoDatasetMultiple)
m.Get("/my_datasets_m", repo.MyDatasetsMultiple)
m.Get("/public_datasets_m", repo.PublicDatasetMultiple)

m.Get("/reference_datasets_available", repo.ReferenceDatasetAvailable)
m.Get("/my_favorite_m", repo.MyFavoriteDatasetMultiple)

m.Group("/status", func() {
@@ -1126,7 +1135,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Post("/del", cloudbrain.AdminOrOwnerOrJobCreaterRightForTrain, repo.CloudBrainTrainJobDel)
//m.Get("/models", reqRepoCloudBrainReader, repo.CloudBrainShowModels)
m.Get("/download_model", cloudbrain.AdminOrOwnerOrJobCreaterRightForTrain, repo.CloudBrainDownloadModel)
//m.Get("/create_version", reqWechatBind, cloudbrain.AdminOrJobCreaterRightForTrain, repo.TrainJobNewVersion)
//m.Get("/get_log", cloudbrain.AdminOrJobCreaterRightForTrain, repo.GetLogFromModelDir)
//m.Post("/create_version", reqWechatBind, cloudbrain.AdminOrJobCreaterRightForTrain, bindIgnErr(auth.CreateModelArtsTrainJobForm{}), repo.TrainJobCreateVersion)
})
m.Get("/create", reqWechatBind, reqRepoCloudBrainWriter, repo.CloudBrainTrainJobNew)
@@ -1209,7 +1218,8 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Group("/:id", func() {
m.Get("", reqRepoCloudBrainReader, repo.NotebookShow)
m.Get("/debug", cloudbrain.AdminOrJobCreaterRight, repo.NotebookDebug2)
m.Post("/:action", reqRepoCloudBrainWriter, repo.NotebookManage)
m.Post("/restart", cloudbrain.AdminOrJobCreaterRight, repo.NotebookRestart)
m.Post("/stop", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.NotebookStop)
m.Post("/del", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.NotebookDel)
})
m.Get("/create", reqWechatBind, reqRepoCloudBrainWriter, repo.NotebookNew)


+ 16
- 17
routers/search.go View File

@@ -349,25 +349,24 @@ func searchRepo(ctx *context.Context, TableName string, Key string, Page int, Pa

func setForkRepoOrder(esresult *SearchRes, SortBy string) {
if SortBy == "default" || SortBy == "" {
return
}
forkidMap := make(map[string]int, 0)
for index, re := range esresult.Result {
if re["fork_id"] != nil {
fork_id := re["fork_id"].(string)
if _, ok := forkidMap[fork_id]; !ok {
forkidMap[fork_id] = index
forkidMap := make(map[string]int, 0)
for index, re := range esresult.Result {
if re["fork_id"] != nil {
fork_id := re["fork_id"].(string)
if _, ok := forkidMap[fork_id]; !ok {
forkidMap[fork_id] = index
}
}
}
}
for key, value := range forkidMap {
for index, re := range esresult.Result {
if re["id"].(string) == key {
if value < index { //swap
tmp := esresult.Result[index]
esresult.Result[index] = esresult.Result[value]
esresult.Result[value] = tmp
break
for key, value := range forkidMap {
for index, re := range esresult.Result {
if re["id"].(string) == key {
if value < index { //swap
tmp := esresult.Result[index]
esresult.Result[index] = esresult.Result[value]
esresult.Result[value] = tmp
break
}
}
}
}


+ 6
- 0
routers/user/home.go View File

@@ -761,10 +761,14 @@ func Cloudbrains(ctx *context.Context) {
listType := ctx.Query("listType")
jobType := ctx.Query("jobType")
jobStatus := ctx.Query("jobStatus")
aiCenter := ctx.Query("aiCenter")
cluster := ctx.Query("cluster")

ctx.Data["ListType"] = listType
ctx.Data["JobType"] = jobType
ctx.Data["JobStatus"] = jobStatus
ctx.Data["aiCenter"] = aiCenter
ctx.Data["cluster"] = cluster

page := ctx.QueryInt("page")
if page <= 0 {
@@ -825,6 +829,8 @@ func Cloudbrains(ctx *context.Context) {
RepoIDList: repoIDList,
ComputeResource: listType,
Type: models.TypeCloudBrainAll,
AiCenter: aiCenter,
Cluster: cluster,
})
if err != nil {
ctx.ServerError("Get job failed:", err)


+ 19
- 0
services/repository/dataset.go View File

@@ -0,0 +1,19 @@
package repository

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

func ConvertToDatasetWithStar(ctx *context.Context, datasets []*models.Dataset) []*models.DatasetWithStar {
var datasetsWithStar []*models.DatasetWithStar
for _, dataset := range datasets {
if !ctx.IsSigned {
datasetsWithStar = append(datasetsWithStar, &models.DatasetWithStar{Dataset: *dataset, IsStaring: false})
} else {
datasetsWithStar = append(datasetsWithStar, &models.DatasetWithStar{Dataset: *dataset, IsStaring: models.IsDatasetStaring(ctx.User.ID, dataset.ID)})
}

}
return datasetsWithStar
}

+ 7
- 3
templates/admin/cloudbrain/list.tmpl View File

@@ -14,6 +14,10 @@
<div class="admin user">
<div class="cloudbrain_debug" style="display: none;" data-debug="{{$.i18n.Tr "repo.debug"}}"
data-debug-again="{{$.i18n.Tr "repo.debug_again"}}"
data-all-cluster="{{.i18n.Tr "cloudbrain.all_resource_cluster"}}"
data-all-aiCenter="{{.i18n.Tr "cloudbrain.all_ai_center"}}"
data-cluster-c2net="{{.i18n.Tr "cloudbrain.resource_cluster_c2net"}}"
data-cluster-openi="{{.i18n.Tr "cloudbrain.resource_cluster_openi"}}"
data-all-task="{{.i18n.Tr "admin.cloudbrain.all_task_types"}}"
data-all-compute="{{.i18n.Tr "admin.cloudbrain.all_computing_resources"}}"
data-all-status="{{.i18n.Tr "admin.cloudbrain.all_status"}}"></div>
@@ -41,12 +45,12 @@
<div class="one wide column text center nowrap" style="width:6% !important;">
<span>{{$.i18n.Tr "repo.modelarts.cluster"}}</span>
</div>
<div class="one wide column text center nowrap" style="width:6% !important;">
<span>{{$.i18n.Tr "repo.cloudbrain_task_type"}}</span>
</div>
<div class="two wide column text center nowrap" style="width: 6% !important;">
<span>{{$.i18n.Tr "repo.modelarts.status"}}</span>
</div>
<div class="one wide column text center nowrap" style="width:6% !important;">
<span>{{$.i18n.Tr "repo.cloudbrain_task_type"}}</span>
</div>
<div class="two wide column text center nowrap" style="width: 8% !important;">
<span>{{$.i18n.Tr "repo.modelarts.createtime"}}</span>
</div>


+ 46
- 22
templates/admin/cloudbrain/search.tmpl View File

@@ -7,44 +7,68 @@
</form>
</div>
<div class="ui ten wide column" style="margin: 1rem 0;" id="adminCloud">
<div class="ui selection dropdown" style="min-width: 10em;min-height:2.6em;border-radius: .28571429rem;margin-right: 1em;padding: .67em 3.2em .7em 1em;">
<div class="default text" style="color: rgba(0,0,0,.87);">{{.i18n.Tr "cloudbrain.all_resource_cluster"}}</div>
<i class="dropdown icon"></i>
<div class="menu">
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster=&aiCenter={{$.aiCenter}}" data-value='{{.i18n.Tr "cloudbrain.all_resource_cluster"}}'>{{.i18n.Tr "cloudbrain.all_resource_cluster"}}</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster=resource_cluster_openi&aiCenter={{$.aiCenter}}" data-value="{{.i18n.Tr "cloudbrain.resource_cluster_openi"}}">{{.i18n.Tr "cloudbrain.resource_cluster_openi"}}</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster=resource_cluster_c2net&aiCenter={{$.aiCenter}}" data-value="{{.i18n.Tr "cloudbrain.resource_cluster_c2net"}}">{{.i18n.Tr "cloudbrain.resource_cluster_c2net"}}</a>
</div>
</div>
<div class="ui selection dropdown" style="min-width: 10em;min-height:2.6em;border-radius: .28571429rem;margin-right: 1em;padding: .67em 3.2em .7em 1em;">
<div class="default text" style="color: rgba(0,0,0,.87);">{{.i18n.Tr "cloudbrain.all_ai_center"}}</div>
<i class="dropdown icon"></i>
<div class="menu">
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter=" data-value='{{.i18n.Tr "cloudbrain.all_ai_center"}}'>{{.i18n.Tr "cloudbrain.all_ai_center"}}</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter=鹏城云计算所" data-value="鹏城云计算所">鹏城云计算所</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter=成都智算" data-value="成都智算">成都智算</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter=合肥类脑" data-value="合肥类脑">合肥类脑</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter=octopus" data-value="octopus">octopus</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter=武汉智算" data-value="武汉智算">武汉智算</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter=西安智算" data-value="西安智算">西安智算</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter=中原智算" data-value="中原智算">中原智算</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter=许昌AI中心" data-value="许昌AI中心">许昌AI中心</a>
</div>
</div>
<div class="ui selection dropdown" style="min-width: 10em;min-height:2.6em;border-radius: .28571429rem;margin-right: 1em;padding: .67em 3.2em .7em 1em;">
<div class="default text" style="color: rgba(0,0,0,.87);">{{.i18n.Tr "admin.cloudbrain.all_task_types"}}</div>
<i class="dropdown icon"></i>
<div class="menu">
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=&listType={{$.ListType}}&jobStatus={{$.JobStatus}}" data-value='{{.i18n.Tr "admin.cloudbrain.all_task_types"}}'>{{.i18n.Tr "admin.cloudbrain.all_task_types"}}</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=DEBUG&listType={{$.ListType}}&jobStatus={{$.JobStatus}}" data-value="DEBUG">DEBUG</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=TRAIN&listType={{$.ListType}}&jobStatus={{$.JobStatus}}" data-value="TRAIN">TRAIN</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=INFERENCE&listType={{$.ListType}}&jobStatus={{$.JobStatus}}" data-value="INFERENCE">INFERENCE</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=BENCHMARK&listType={{$.ListType}}&jobStatus={{$.JobStatus}}" data-value="BENCHMARK">BENCHMARK</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=SNN4IMAGENET&listType={{$.ListType}}&jobStatus={{$.JobStatus}}" data-value="SNN4IMAGENET">SNN4IMAGENET</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=BRAINSCORE&listType={{$.ListType}}&jobStatus={{$.JobStatus}}" data-value="BRAINSCORE">BRAINSCORE</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value='{{.i18n.Tr "admin.cloudbrain.all_task_types"}}'>{{.i18n.Tr "admin.cloudbrain.all_task_types"}}</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=DEBUG&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="DEBUG">DEBUG</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=TRAIN&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="TRAIN">TRAIN</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=INFERENCE&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="INFERENCE">INFERENCE</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=BENCHMARK&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="BENCHMARK">BENCHMARK</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=SNN4IMAGENET&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="SNN4IMAGENET">SNN4IMAGENET</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=BRAINSCORE&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="BRAINSCORE">BRAINSCORE</a>
</div>
</div>
<div class="ui selection dropdown" style="min-width: 10em;min-height:2.6em;border-radius: .28571429rem;margin-right: 1em;padding: .67em 3.2em .7em 1em;">
<div class="default text" style="color: rgba(0,0,0,.87);">{{.i18n.Tr "admin.cloudbrain.all_computing_resources"}}</div>
<i class="dropdown icon"></i>
<div class="menu">
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType=&jobStatus={{$.JobStatus}}" data-value='{{.i18n.Tr "admin.cloudbrain.all_computing_resources"}}'>{{.i18n.Tr "admin.cloudbrain.all_computing_resources"}}</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType=CPU/GPU&jobStatus={{$.JobStatus}}" data-value="CPU/GPU">CPU/GPU</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType=NPU&jobStatus={{$.JobStatus}}" data-value="NPU">NPU</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType=&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value='{{.i18n.Tr "admin.cloudbrain.all_computing_resources"}}'>{{.i18n.Tr "admin.cloudbrain.all_computing_resources"}}</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType=CPU/GPU&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="CPU/GPU">CPU/GPU</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType=NPU&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="NPU">NPU</a>
</div>
</div>
<div class="ui selection dropdown" style="min-width: 10em;min-height:2.6em;border-radius: .28571429rem;margin-right: 1em;padding: .67em 3.2em .7em 1em;">
<div class="default text" style="color: rgba(0,0,0,.87);">{{.i18n.Tr "admin.cloudbrain.all_status"}}</div>
<i class="dropdown icon"></i>
<div class="menu">
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=" data-value='{{.i18n.Tr "admin.cloudbrain.all_status"}}'>{{.i18n.Tr "admin.cloudbrain.all_status"}}</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=STARTING" data-value="STARTING">STARTING</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=RUNNING" data-value="RUNNING">RUNNING</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=RESTARTING" data-value="RESTARTING">RESTARTING </a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=START_FAILED" data-value="START_FAILED">START_FAILED</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=STOPPING" data-value="STOPPING">STOPPING</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=STOPPED" data-value="STOPPED">STOPPED</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=WAITING" data-value="WAITING">WAITING</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=COMPLETED" data-value="COMPLETED">COMPLETED</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=SUCCEEDED" data-value="SUCCEEDED">SUCCEEDED</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=FAILED" data-value="FAILED">FAILED </a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=other" data-value="OTHER">OTHER</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value='{{.i18n.Tr "admin.cloudbrain.all_status"}}'>{{.i18n.Tr "admin.cloudbrain.all_status"}}</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=STARTING&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="STARTING">STARTING</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=RUNNING&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="RUNNING">RUNNING</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=RESTARTING&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="RESTARTING">RESTARTING </a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=START_FAILED&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="START_FAILED">START_FAILED</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=STOPPING&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="STOPPING">STOPPING</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=STOPPED&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="STOPPED">STOPPED</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=WAITING&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="WAITING">WAITING</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=COMPLETED&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="COMPLETED">COMPLETED</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=SUCCEEDED&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="SUCCEEDED">SUCCEEDED</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=FAILED&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="FAILED">FAILED </a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=other&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="OTHER">OTHER</a>
</div>
</div>

+ 46
- 22
templates/admin/cloudbrain/search_dashboard.tmpl View File

@@ -19,44 +19,68 @@
<div class="ui grid">
<div class="row">
<div class="ui {{if $.PageIsUserCloudBrain}}sixteen{{else}}six{{end}} wide column" style="margin: 1rem 0;" id="userCloud">
<div class="ui selection dropdown" style="min-width: 10em;min-height:2.6em;border-radius: .28571429rem;margin-right: 1em;padding: .67em 3.2em .7em 1em;">
<div class="default text" style="color: rgba(0,0,0,.87);">{{.i18n.Tr "cloudbrain.all_resource_cluster"}}</div>
<i class="dropdown icon"></i>
<div class="menu">
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster=&aiCenter={{$.aiCenter}}" data-value='{{.i18n.Tr "cloudbrain.all_resource_cluster"}}'>{{.i18n.Tr "cloudbrain.all_resource_cluster"}}</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster=resource_cluster_openi&aiCenter={{$.aiCenter}}" data-value="{{.i18n.Tr "cloudbrain.resource_cluster_openi"}}">{{.i18n.Tr "cloudbrain.resource_cluster_openi"}}</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster=resource_cluster_c2net&aiCenter={{$.aiCenter}}" data-value="{{.i18n.Tr "cloudbrain.resource_cluster_c2net"}}">{{.i18n.Tr "cloudbrain.resource_cluster_c2net"}}</a>
</div>
</div>
<div class="ui selection dropdown" style="min-width: 10em;min-height:2.6em;border-radius: .28571429rem;margin-right: 1em;padding: .67em 3.2em .7em 1em;">
<div class="default text" style="color: rgba(0,0,0,.87);">{{.i18n.Tr "cloudbrain.all_ai_center"}}</div>
<i class="dropdown icon"></i>
<div class="menu">
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter=" data-value='{{.i18n.Tr "cloudbrain.all_ai_center"}}'>{{.i18n.Tr "cloudbrain.all_ai_center"}}</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter=鹏城云计算所" data-value="鹏城云计算所">鹏城云计算所</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter=成都智算" data-value="成都智算">成都智算</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter=合肥类脑" data-value="合肥类脑">合肥类脑</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter=octopus" data-value="octopus">octopus</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter=武汉智算" data-value="武汉智算">武汉智算</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter=西安智算" data-value="西安智算">西安智算</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter=中原智算" data-value="中原智算">中原智算</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter=许昌AI中心" data-value="许昌AI中心">许昌AI中心</a>
</div>
</div>
<div class="ui selection dropdown" style="min-width: 10em;min-height:2.6em;border-radius: .28571429rem;margin-right: 1em;padding: .67em 3.2em .7em 1em;">
<div class="default text" style="color: rgba(0,0,0,.87);">{{.i18n.Tr "admin.cloudbrain.all_task_types"}}</div>
<i class="dropdown icon"></i>
<div class="menu">
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=&listType={{$.ListType}}&jobStatus={{$.JobStatus}}" data-value='{{.i18n.Tr "admin.cloudbrain.all_task_types"}}'>{{.i18n.Tr "admin.cloudbrain.all_task_types"}}</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=DEBUG&listType={{$.ListType}}&jobStatus={{$.JobStatus}}" data-value="DEBUG">{{.i18n.Tr "cloudbrain.DEBUG"}}</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=TRAIN&listType={{$.ListType}}&jobStatus={{$.JobStatus}}" data-value="TRAIN">{{.i18n.Tr "cloudbrain.TRAIN"}}</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=INFERENCE&listType={{$.ListType}}&jobStatus={{$.JobStatus}}" data-value="INFERENCE">{{.i18n.Tr "cloudbrain.INFERENCE"}}</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=BENCHMARK&listType={{$.ListType}}&jobStatus={{$.JobStatus}}" data-value="BENCHMARK">{{.i18n.Tr "cloudbrain.BENCHMARK"}}</a>
<!-- <a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=SNN4IMAGENET&listType={{$.ListType}}&jobStatus={{$.JobStatus}}" data-value="BENCHMARK">{{.i18n.Tr "cloudbrain.SNN4IMAGENET"}}</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=BRAINSCORE&listType={{$.ListType}}&jobStatus={{$.JobStatus}}" data-value="BENCHMARK">{{.i18n.Tr "cloudbrain.BRAINSCORE"}}</a> -->
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value='{{.i18n.Tr "admin.cloudbrain.all_task_types"}}'>{{.i18n.Tr "admin.cloudbrain.all_task_types"}}</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=DEBUG&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="DEBUG">{{.i18n.Tr "cloudbrain.DEBUG"}}</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=TRAIN&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="TRAIN">{{.i18n.Tr "cloudbrain.TRAIN"}}</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=INFERENCE&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="INFERENCE">{{.i18n.Tr "cloudbrain.INFERENCE"}}</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=BENCHMARK&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="BENCHMARK">{{.i18n.Tr "cloudbrain.BENCHMARK"}}</a>
<!-- <a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=SNN4IMAGENET&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="BENCHMARK">{{.i18n.Tr "cloudbrain.SNN4IMAGENET"}}</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=BRAINSCORE&listType={{$.ListType}}&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="BENCHMARK">{{.i18n.Tr "cloudbrain.BRAINSCORE"}}</a> -->
</div>
</div>
<div class="ui selection dropdown" style="min-width: 10em;min-height:2.6em;border-radius: .28571429rem;margin-right: 1em;padding: .67em 3.2em .7em 1em;">
<div class="default text" style="color: rgba(0,0,0,.87);">{{.i18n.Tr "admin.cloudbrain.all_computing_resources"}}</div>
<i class="dropdown icon"></i>
<div class="menu">
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType=&jobStatus={{$.JobStatus}}" data-value='{{.i18n.Tr "admin.cloudbrain.all_computing_resources"}}'>{{.i18n.Tr "admin.cloudbrain.all_computing_resources"}}</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType=CPU/GPU&jobStatus={{$.JobStatus}}" data-value="CPU/GPU">CPU/GPU</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType=NPU&jobStatus={{$.JobStatus}}" data-value="NPU">NPU</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType=&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value='{{.i18n.Tr "admin.cloudbrain.all_computing_resources"}}'>{{.i18n.Tr "admin.cloudbrain.all_computing_resources"}}</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType=CPU/GPU&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="CPU/GPU">CPU/GPU</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType=NPU&jobStatus={{$.JobStatus}}&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="NPU">NPU</a>
</div>
</div>
<div class="ui selection dropdown" style="min-width: 10em;min-height:2.6em;border-radius: .28571429rem;margin-right: 1em;padding: .67em 3.2em .7em 1em;">
<div class="default text" style="color: rgba(0,0,0,.87);">{{.i18n.Tr "admin.cloudbrain.all_status"}}</div>
<i class="dropdown icon"></i>
<div class="menu">
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=" data-value='{{.i18n.Tr "admin.cloudbrain.all_status"}}'>{{.i18n.Tr "admin.cloudbrain.all_status"}}</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=STARTING" data-value="STARTING">STARTING</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=RUNNING" data-value="RUNNING">RUNNING</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=RESTARTING" data-value="RESTARTING">RESTARTING </a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=START_FAILED" data-value="START_FAILED">START_FAILED</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=STOPPING" data-value="STOPPING">STOPPING</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=STOPPED" data-value="STOPPED">STOPPED</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=WAITING" data-value="WAITING">WAITING</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=COMPLETED" data-value="COMPLETED">COMPLETED</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=SUCCEEDED" data-value="SUCCEEDED">SUCCEEDED</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=FAILED" data-value="FAILED">FAILED </a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=other" data-value="OTHER">OTHER</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value='{{.i18n.Tr "admin.cloudbrain.all_status"}}'>{{.i18n.Tr "admin.cloudbrain.all_status"}}</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=STARTING&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="STARTING">STARTING</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=RUNNING&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="RUNNING">RUNNING</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=RESTARTING&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="RESTARTING">RESTARTING </a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=START_FAILED&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="START_FAILED">START_FAILED</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=STOPPING&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="STOPPING">STOPPING</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=STOPPED&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="STOPPED">STOPPED</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=WAITING&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="WAITING">WAITING</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=COMPLETED&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="COMPLETED">COMPLETED</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=SUCCEEDED&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="SUCCEEDED">SUCCEEDED</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=FAILED&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="FAILED">FAILED </a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=other&cluster={{$.cluster}}&aiCenter={{$.aiCenter}}" data-value="OTHER">OTHER</a>
</div>
</div>


+ 10
- 10
templates/custom/select_dataset_train.tmpl View File

@@ -15,7 +15,7 @@
{{if .benchmarkMode}}{{.i18n.Tr "repo.modelarts.infer_job.select_model"}}{{else}}{{.i18n.Tr "dataset.select_dataset"}}{{end}}
</el-button>
{{if .benchmarkMode}}
<span class="tooltips" style="display: block;margin-left:11.5rem;">说明:先使用数据集功能上传模型,然后从数据集列表选模型。</span>
<span class="tooltips" style="display: block;margin-left:11.5rem;">{{.i18n.Tr "dataset.benchmark_dataset_tip"}}</span>
{{end}}
<el-dialog title="{{.i18n.Tr "dataset.select_dataset"}}" :visible.sync="dialogVisible" width="50%">
<div v-loading="loadingDataIndex" style="position: relative;">
@@ -49,13 +49,13 @@
<i class="CREATING"></i>
<span style="margin-left: 0.4em;font-size: 12px;color: #5A5A5A;"
data-tooltip="{{$.i18n.Tr "dataset.unzip_tooltips"}}" data-inverted=""
data-variation="mini" data-position="left center">解压中</span>
data-variation="mini" data-position="left center">{{$.i18n.Tr "dataset.unzip_stared"}}</span>
</span>
<span v-if="dataset.DecompressState===3" style="display: flex;align-items: center;">
<i class="FAILED"></i>
<span style="margin-left: 0.4em;font-size: 12px;color:red;"
data-tooltip="{{$.i18n.Tr "dataset.zip_failed"}}" data-inverted=""
data-variation="mini" data-position="left center">解压失败</span>
data-tooltip="{{$.i18n.Tr "dataset.unzip_failed"}}" data-inverted=""
data-variation="mini" data-position="left center">{{$.i18n.Tr "dataset.unzip_failed"}}</span>
</span>
</div>
</div>
@@ -85,13 +85,13 @@
<i class="CREATING"></i>
<span style="margin-left: 0.4em;font-size: 12px;color: #5A5A5A;"
data-tooltip="{{$.i18n.Tr "dataset.unzip_tooltips"}}" data-inverted=""
data-variation="mini" data-position="left center">解压中</span>
data-variation="mini" data-position="left center">{{$.i18n.Tr "dataset.unzip_stared"}}</span>
</span>
<span v-if="dataset.DecompressState===3" style="display: flex;align-items: center;">
<i class="FAILED"></i>
<span style="margin-left: 0.4em;font-size: 12px;color:red;"
data-tooltip="{{$.i18n.Tr "dataset.zip_failed"}}" data-inverted=""
data-variation="mini" data-position="left center">解压失败</span>
data-variation="mini" data-position="left center">{{$.i18n.Tr "dataset.unzip_failed"}}</span>
</span>
</div>
</div>
@@ -120,13 +120,13 @@
<i class="CREATING"></i>
<span style="margin-left: 0.4em;font-size: 12px;color: #5A5A5A;"
data-tooltip="{{$.i18n.Tr "dataset.unzip_tooltips"}}" data-inverted=""
data-variation="mini" data-position="left center">解压中</span>
data-variation="mini" data-position="left center">{{$.i18n.Tr "dataset.unzip_stared"}}</span>
</span>
<span v-if="dataset.DecompressState===3" style="display: flex;align-items: center;">
<i class="FAILED"></i>
<span style="margin-left: 0.4em;font-size: 12px;color:red;"
data-tooltip="{{$.i18n.Tr "dataset.zip_failed"}}" data-inverted=""
data-variation="mini" data-position="left center">解压失败</span>
data-variation="mini" data-position="left center">{{$.i18n.Tr "dataset.unzip_failed"}}</span>
</span>
</div>
</div>
@@ -155,13 +155,13 @@
<i class="CREATING"></i>
<span style="margin-left: 0.4em;font-size: 12px;color: #5A5A5A;"
data-tooltip="{{$.i18n.Tr "dataset.unzip_tooltips"}}" data-inverted=""
data-variation="mini" data-position="left center">解压中</span>
data-variation="mini" data-position="left center">{{$.i18n.Tr "dataset.unzip_stared"}}</span>
</span>
<span v-if="dataset.DecompressState===3" style="display: flex;align-items: center;">
<i class="FAILED"></i>
<span style="margin-left: 0.4em;font-size: 12px;color:red;"
data-tooltip="{{$.i18n.Tr "dataset.zip_failed"}}" data-inverted=""
data-variation="mini" data-position="left center">解压失败</span>
data-variation="mini" data-position="left center">{{$.i18n.Tr "dataset.unzip_failed"}}</span>
</span>
</div>
</div>


+ 2
- 2
templates/custom/wait_count.tmpl View File

@@ -13,9 +13,9 @@
{{ end }}
<i
class="ri-error-warning-line"
style="margin-right: 0.5rem; font-size: 16px"
style="margin-right: 0.5rem; font-size: 14px"
></i>
<span id="gpu-nums"
<span id="gpu-nums" style="font-size: 12px"
>{{.i18n.Tr "repo.wait_count_start"}}
{{if .QueuesDetail}}
{{ $gpuQueue }}


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

@@ -14,9 +14,9 @@
{{ end }}
<i
class="ri-error-warning-line"
style="margin-right: 0.5rem; font-size: 16px"
style="margin-right: 0.5rem; font-size: 14px"
></i>
<span id="gpu-nums"
<span id="gpu-nums" style="font-size: 12px"
>{{.ctx.i18n.Tr "repo.wait_count_start"}}
{{if .type}}
{{ $gpuQueue }}


+ 9
- 8
templates/home.tmpl View File

@@ -89,8 +89,8 @@
<div class="ui vertical masthead secondary c2net segment">
<div class="ui container">
<div class="ui center am-pt-30 am-pb-30">
<h2>智算网络</h2>
<p><span class="ui text grey">人工智能算力网络推进联盟已接入11家智算中心,算力总规模1924P</p>
<h2>{{.i18n.Tr "home.c2net_title"}}</h2>
<p><span class="ui text grey">{{.i18n.Tr "home.c2net_desc"}}</p>
</div>

<div id="app" v-cloak>
@@ -98,7 +98,7 @@
<div class="rotation3D-baseMap"></div>
<!--旋转3D-->
<div id="rotation3D" class="rotation3D">
<button class="center">中心</button>
<button class="center">{{.i18n.Tr "home.c2net_center"}}</button>
<div class="itemList">
<div class="rotation3D__item" :class="item.type" v-for="item in itemList">
@@ -200,22 +200,23 @@
<div class="six wide column">
<img class="ui centered large image" src="/img/i-yunnao.svg">
</div>
<div class="ten wide column am-pt-30">
<div class="ten wide column">
<h2 class="ui grey inverted header">{{.page_dev_yunlao}}</h2>
<p class="am-lh-18 ui text grey">
{{.page_dev_yunlao_desc1}}<br>
{{.page_dev_yunlao_desc2}}<br>
{{.page_dev_yunlao_desc3}}<br>
{{.page_dev_yunlao_desc4}}<br>
{{.page_dev_yunlao_desc4}}<br>
{{.page_dev_yunlao_desc5}}<br>
</p>
{{if .IsSigned}}
<a class="ui blue basic button am-mt-20" href="{{AppSubUrl}}/dashboard">{{.page_use}}</a>
<a class="ui blue basic button am-mt-10" href="{{AppSubUrl}}/dashboard">{{.page_use}}</a>
{{else}}
<a class="ui blue basic button am-mt-20" href="{{AppSubUrl}}/user/login">{{.page_use}}</a>
<a class="ui blue basic button am-mt-10" href="{{AppSubUrl}}/user/login">{{.page_use}}</a>
{{end}}
<a class="ui grey basic button am-mt-20" href="mailto:aiforge@openi.org.cn">{{.page_dev_yunlao_apply}}</a>
<a class="ui grey basic button am-mt-10" href="mailto:aiforge@openi.org.cn">{{.page_dev_yunlao_apply}}</a>
</div>
</div>
</div>


+ 2
- 1
templates/repo/attachment/upload.tmpl View File

@@ -47,7 +47,8 @@
data-uploading='{{.i18n.Tr "dropzone.uploading"}}'
data-failed='{{.i18n.Tr "dropzone.failed"}}'
data-repopath='{{AppSubUrl}}{{$.RepoLink}}/datasets' data-cancel='{{.i18n.Tr "cancel"}}'
data-upload='{{.i18n.Tr "dataset.dataset_upload"}}'>
data-upload='{{.i18n.Tr "dataset.dataset_upload"}}'
data-upload-status='{{.i18n.Tr "dataset.dataset_upload_status"}}'>
</div>
<div id="datasetId" datasetId="{{.datasetId}}"></div>
</el-form>


+ 12
- 10
templates/repo/cloudbrain/benchmark/new.tmpl View File

@@ -40,7 +40,7 @@
<input type="hidden" name="benchmarkMode" value="{{.benchmarkMode}}">

{{if eq .benchmarkMode "model"}}
<form class="ui form model_form" action="{{.Link}}?benchmarkMode=model" method="post">
<form id="form_id" class="ui form model_form" action="{{.Link}}?benchmarkMode=model" method="post">
{{.CsrfTokenHtml}}
<input type="hidden" name="action" value="update">
<div class="required min_title inline field">
@@ -134,7 +134,7 @@
</div>
</form>
{{else}}
<form class="ui form alogrithm_form" action="{{.Link}}?benchmarkMode=alogrithm" method="post">
<form id="form_id" class="ui form alogrithm_form" action="{{.Link}}?benchmarkMode=alogrithm" method="post">
{{.CsrfTokenHtml}}
<input type="hidden" name="action" value="update">
<input type="hidden" name="job_type" value="BENCHMARK">
@@ -178,8 +178,7 @@
</div>
<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>
<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">
@@ -193,12 +192,9 @@
</select>
</div>
<div class="eight wide field" id="engine_name">
<input type="hidden" id="benchmark_child_types_id_hidden"
name="benchmark_child_types_id_hidden" value="{{.benchmark_child_types_id_hidden}}">
<label
style="font-weight: normal;white-space: nowrap;">{{.i18n.Tr "repo.cloudbrain.benchmark.evaluate_child_type"}}</label>
<select class="ui fluid selection dropdown nowrapx" id="benchmark_child_types_id"
style='width: 100%;' name="benchmark_child_types_id">
<input type="hidden" id="benchmark_child_types_id_hidden" name="benchmark_child_types_id_hidden" value="{{.benchmark_child_types_id_hidden}}">
<label style="font-weight: normal;white-space: nowrap;">{{.i18n.Tr "repo.cloudbrain.benchmark.evaluate_child_type"}}</label>
<select class="ui fluid selection dropdown nowrapx" id="benchmark_child_types_id" style='width: 100%;' name="benchmark_child_types_id">
</select>
</div>
</div>
@@ -251,6 +247,12 @@
{{template "base/footer" .}}

<script>
let form = document.getElementById('form_id');
let createFlag = false
form.onsubmit = function (e) {
if(createFlag) return false
createFlag = true
}
let repolink = {{.RepoLink }}
let url_href = window.location.pathname.split('create')[0]
$(".ui.button").attr('href', url_href)


+ 22
- 8
templates/repo/cloudbrain/inference/new.tmpl View File

@@ -47,7 +47,7 @@
</h4>
<div class="ui attached segment">
<!-- equal width -->
<form class="ui form" action="{{.Link}}" method="post">
<form id="form_id" class="ui form" action="{{.Link}}" method="post">
{{.CsrfTokenHtml}}
<input type="hidden" name="action" value="update">
<input type="hidden" id="ai_image_name" value="{{.image}}">
@@ -83,6 +83,10 @@
Ascend NPU</a>
</div>
{{template "custom/wait_count_train" Dict "ctx" $ "type" .inference_gpu_types}}
<div style="display: flex;align-items: center;margin-left: 155px;margin-top: 0.5rem;">
<i class="ri-error-warning-line" style="color: #f2711c;margin-right: 0.5rem;"></i>
<span style="color: #888;font-size: 12px;">{{.i18n.Tr "cloudbrain.new_infer_gpu_tooltips" "/dataset" "/model" "/result" | Safe}}</span>
</div>
</div>
<div class="required min_title inline field">
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.job_name"}}</label>
@@ -186,8 +190,10 @@
{{end}}
</select>
</div>
<!-- 数据集 -->
{{template "custom/select_dataset_train" .}}
<!-- 数据集-->
<div id="select-multi-dataset">

</div>
<span class="tooltips" style="margin-left: 11.5rem;margin-bottom: 1rem;"></span>
<div class="inline min_title field required">
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.start_file"}}</label>
@@ -227,18 +233,18 @@
{{if .resource_spec_id}}
{{range .inference_resource_specs}}
{{if eq $.resource_spec_id .Id}}
<option value="{{.Id}}">GPU数:{{.GpuNum}},CPU数:{{.CpuNum}},内存(MB):{{.MemMiB}},共享内存(MB):{{.ShareMemMiB}}</option>
<option value="{{.Id}}">{{$.i18n.Tr "cloudbrain.gpu_num"}}:{{.GpuNum}},{{$.i18n.Tr "cloudbrain.cpu_num"}}:{{.CpuNum}},{{$.i18n.Tr "cloudbrain.memory"}}(MB):{{$.i18n.Tr "cloudbrain.shared_memory"}}(MB):{{.ShareMemMiB}}</option>
{{end}}
{{end}}
{{range .inference_resource_specs}}
{{if ne $.resource_spec_id .Id}}
<option value="{{.Id}}">GPU数:{{.GpuNum}},CPU数:{{.CpuNum}},内存(MB):{{.MemMiB}},共享内存(MB):{{.ShareMemMiB}}</option>
<option value="{{.Id}}">{{$.i18n.Tr "cloudbrain.gpu_num"}}:{{.GpuNum}},{{$.i18n.Tr "cloudbrain.cpu_num"}}:{{.CpuNum}},{{$.i18n.Tr "cloudbrain.memory"}}(MB):{{$.i18n.Tr "cloudbrain.shared_memory"}}(MB):{{.ShareMemMiB}}</option>
{{end}}
{{end}}
{{else}}
{{range .inference_resource_specs}}
<option name="resource_spec_id" value="{{.Id}}">
GPU数:{{.GpuNum}},CPU数:{{.CpuNum}},内存(MB):{{.MemMiB}},共享内存(MB):{{.ShareMemMiB}}</option>
{{$.i18n.Tr "cloudbrain.gpu_num"}}:{{.GpuNum}},{{$.i18n.Tr "cloudbrain.cpu_num"}}:{{.CpuNum}},{{$.i18n.Tr "cloudbrain.memory"}}(MB):{{$.i18n.Tr "cloudbrain.shared_memory"}}(MB):{{.ShareMemMiB}}</option>
{{end}}
{{end}}
</select>
@@ -260,6 +266,12 @@
{{template "base/footer" .}}

<script>
let form = document.getElementById('form_id');
let createFlag = false
form.onsubmit = function (e) {
if(createFlag) return false
createFlag = true
}
const RepoLink = {{.RepoLink}}
let nameMap,nameList
// 获取模型列表和模型名称对应的模型版本
@@ -376,17 +388,19 @@
let value = ''
value += `<div class="two fields width85" id= "para${i}">`
value += '<div class="field">'
let placeholder_value='{{.i18n.Tr "repo.modelarts.train_job.parameter_value"}}'
let placeholder_name='{{.i18n.Tr "repo.modelarts.train_job.parameter_name"}}'
if(flag){
value +=`<input type="text" class="shipping_first-name" value="${paramsObject.label}">`
}else{
value +='<input type="text" class="shipping_first-name" required placeholder={{.i18n.Tr "repo.modelarts.train_job.parameter_name"}}>'
value +='<input type="text" class="shipping_first-name" required placeholder="' + placeholder_name+ '">'
}
value += '</div>'
value += '<div class="field">'
if(flag){
value +=`<input type="text" class="shipping_last-name" value="${paramsObject.value}">`
}else{
value +='<input type="text" class="shipping_last-name" required placeholder={{.i18n.Tr "repo.modelarts.train_job.parameter_value"}}>'
value +='<input type="text" class="shipping_last-name" required placeholder="' + placeholder_value+ '">'
}
value += '</div>'
value += '<span><i class="trash icon"></i></span>'


+ 19
- 15
templates/repo/cloudbrain/inference/show.tmpl View File

@@ -248,7 +248,7 @@
class="cti-mgRight-sm">{{$.i18n.Tr "repo.modelarts.train_job.dura_time"}}:</span>
<span class="cti-mgRight-sm uc-accordionTitle-black"
id="{{.VersionName}}-duration-span">{{$.duration}}</span>
<span id="refresh-status" data-tooltip="刷新" style="cursor: pointer;" data-inverted="" data-version="{{.VersionName}}"><i
<span class="refresh-status" data-tooltip="刷新" style="cursor: pointer;" data-inverted="" data-version="{{.VersionName}}"><i
class="redo icon redo-color"></i></span>

</div>
@@ -268,7 +268,7 @@
<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>
<div class="ui tab active" data-tab="first" style="height:400px">
<div class="ui tab active" data-tab="first">
<div style="padding-top: 10px;">
<div class="tab_2_content">
<div class="ac-grid ac-grid-col2">
@@ -461,19 +461,7 @@
</div>
</td>
</tr>
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "repo.modelarts.infer_dataset"}}
</td>

<td class="ti-text-form-content">
<div class="text-span text-span-w">
{{range $m ,$n := $.datasetDownload}}
<a href="{{.RepositoryLink}}" target="_blank">{{.DatasetName}}</a>
{{end}}
</div>
</td>
</tr>
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80" >
{{$.i18n.Tr "repo.modelarts.train_job.run_parameter"}}
@@ -504,6 +492,22 @@
</table>
</div>
</div>
<div style="clear:both">
<table style="border:none" class="ui fixed small stackable table">
<thead>
<tr><th style="color: #8a8e99;font-size:12px" class="three wide left aligned">{{$.i18n.Tr "dataset.file"}}</th>
</tr></thead>
<tbody>
{{range $m ,$n := $.datasetDownload}}
<tr>
<td style="word-wrap: break-word;word-break: break-all;"><a href="{{.RepositoryLink}}" target="_blank">{{.DatasetName}}</a></td>
</tr>
{{end}}

</tbody>
</table>
</div>
</div>

</div>


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

@@ -217,7 +217,9 @@
})
}
validate();
let createFlag = false
form.onsubmit = function (e) {
if(createFlag) return false
let value_task = $("input[name='display_job_name']").val()
let value_image = $("input[name='image']").val()
let value_data = $("input[name='attachment']").val()
@@ -231,6 +233,7 @@
}
let min_value_task = value_task.toLowerCase()
$("input[name='display_job_name']").attr("value", min_value_task)
createFlag = true
document.getElementById("mask").style.display = "block"
}

@@ -276,13 +279,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)
})

</script>

+ 30
- 28
templates/repo/cloudbrain/show.tmpl View File

@@ -252,7 +252,7 @@
</span>
<span class="cti-mgRight-sm uc-accordionTitle-black"
id="{{.VersionName}}-duration-span">{{$.duration}}</span>
<span id="refresh-status" data-tooltip="刷新" style="cursor: pointer;" data-inverted="" data-version="{{.VersionName}}">
<span class="refresh-status" data-tooltip="刷新" style="cursor: pointer;" data-inverted="" data-version="{{.VersionName}}">
<i class="redo icon redo-color"></i>
</span>
</div>
@@ -364,18 +364,7 @@
</td>
</tr>

<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "repo.modelarts.train_job.dura_time"}}
</td>

<td class="ti-text-form-content">
<div class="text-span text-span-w"
id="{{.VersionName}}-duration">
{{$.duration}}
</div>
</td>
</tr>



@@ -404,20 +393,7 @@
</div>
</td>
</tr>
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "repo.modelarts.train_job.dataset"}}
</td>

<td class="ti-text-form-content">
<div class="text-span text-span-w"
id="{{.VersionName}}-BenchmarkTypeName">
{{range $m ,$n := $.datasetDownload}}
<a href="{{.RepositoryLink}}">{{.DatasetName}}</a>
{{end}}
</div>
</td>
</tr>

<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
@@ -496,14 +472,40 @@
</div>
</td>
</tr>
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "repo.modelarts.train_job.dura_time"}}
</td>

<td class="ti-text-form-content">
<div class="text-span text-span-w"
id="{{.VersionName}}-duration">
{{$.duration}}
</div>
</td>
</tr>

</tbody>
</table>
</div>
</div>
</div>

<div style="clear:both">
<table style="border:none" class="ui fixed small stackable table">
<thead>
<tr><th style="color: #8a8e99;font-size:12px" class="three wide left aligned">{{$.i18n.Tr "dataset.file"}}</th>
</tr></thead>
<tbody>
{{range $m ,$n := $.datasetDownload}}
<tr>
<td style="word-wrap: break-word;word-break: break-all;"><a href="{{.RepositoryLink}}" target="_blank">{{.DatasetName}}</a></td>
</tr>
{{end}}

</tbody>
</table>
</div>
</div>
</div>
<div class="ui tab" data-tab="second{{$k}}">


+ 20
- 9
templates/repo/cloudbrain/trainjob/new.tmpl View File

@@ -75,7 +75,7 @@
</h4>
<div class="ui attached segment">
<!-- equal width -->
<form class="ui form" action="{{.Link}}" method="post">
<form id="form_id" class="ui form" action="{{.Link}}" method="post">
{{.CsrfTokenHtml}}
<input type="hidden" name="action" value="update">
<input type="hidden" id="ai_image_name" value="{{.image}}">
@@ -115,6 +115,10 @@
Ascend NPU</a>
</div>
{{template "custom/wait_count_train" Dict "ctx" $ "type" .train_gpu_types}}
<div style="display: flex;align-items: center;margin-left: 155px;margin-top: 0.5rem;">
<i class="ri-error-warning-line" style="color: #f2711c;margin-right: 0.5rem;"></i>
<span style="color: #888;font-size: 12px;">{{.i18n.Tr "cloudbrain.new_train_gpu_tooltips" "/code" "/dataset" "/model" | Safe}}</span>
</div>
</div>
<div class="required min_title inline field">
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.job_name"}}</label>
@@ -207,13 +211,12 @@
data-content={{.i18n.Tr "repo.modelarts.train_job.boot_file_helper"}}
data-position="right center" data-variation="mini"></i>
</span>
<a href="https://git.openi.org.cn/OpenIOSSG/MNIST_PytorchExample_GPU" target="_blank">查看样例</a>
<a href="https://git.openi.org.cn/OpenIOSSG/MNIST_PytorchExample_GPU" target="_blank">{{.i18n.Tr "cloudbrain.view_sample"}}</a>
</div>
<div id="select-multi-dataset">

</div>
<span class="tooltips"
style="margin-left: 11.5rem;margin-bottom: 1rem;">训练脚本存储在/code中,数据集存储在/dataset中,训练输出请存储在/model中以供后续下载。</span>
<span class="tooltips" style="margin-left: 11.5rem;margin-bottom: 1rem;"></span>
<div class="inline min_title field">
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.run_parameter"}}</label>
<span id="add_run_para"
@@ -231,18 +234,18 @@
{{if .resource_spec_id}}
{{range .train_resource_specs}}
{{if eq $.resource_spec_id .Id}}
<option value="{{.Id}}">GPU数:{{.GpuNum}},CPU数:{{.CpuNum}},内存(MB):{{.MemMiB}},共享内存(MB):{{.ShareMemMiB}}</option>
<option value="{{.Id}}">{{$.i18n.Tr "cloudbrain.gpu_num"}}:{{.GpuNum}},{{$.i18n.Tr "cloudbrain.cpu_num"}}:{{.CpuNum}},{{$.i18n.Tr "cloudbrain.memory"}}(MB):{{.MemMiB}},{{$.i18n.Tr "cloudbrain.shared_memory"}}(MB):{{.ShareMemMiB}}</option>
{{end}}
{{end}}
{{range .train_resource_specs}}
{{if ne $.resource_spec_id .Id}}
<option value="{{.Id}}">GPU数:{{.GpuNum}},CPU数:{{.CpuNum}},内存(MB):{{.MemMiB}},共享内存(MB):{{.ShareMemMiB}}</option>
<option value="{{.Id}}">{{$.i18n.Tr "cloudbrain.gpu_num"}}:{{.GpuNum}},{{$.i18n.Tr "cloudbrain.cpu_num"}}:{{.CpuNum}},{{$.i18n.Tr "cloudbrain.memory"}}(MB):{{.MemMiB}},{{$.i18n.Tr "cloudbrain.shared_memory"}}(MB):{{.ShareMemMiB}}</option>
{{end}}
{{end}}
{{else}}
{{range .train_resource_specs}}
<option name="resource_spec_id" value="{{.Id}}">
GPU数:{{.GpuNum}},CPU数:{{.CpuNum}},内存(MB):{{.MemMiB}},共享内存(MB):{{.ShareMemMiB}}</option>
{{$.i18n.Tr "cloudbrain.gpu_num"}}:{{.GpuNum}},{{$.i18n.Tr "cloudbrain.cpu_num"}}:{{.CpuNum}},{{$.i18n.Tr "cloudbrain.memory"}}(MB):{{.MemMiB}},{{$.i18n.Tr "cloudbrain.shared_memory"}}(MB):{{.ShareMemMiB}}</option>
{{end}}
{{end}}
</select>
@@ -266,6 +269,12 @@
{{template "base/footer" .}}

<script>
let form = document.getElementById('form_id');
let createFlag = false
form.onsubmit = function (e) {
if(createFlag) return false
createFlag = true
}
$('select.dropdown')
.dropdown();

@@ -288,17 +297,19 @@
let value = ''
value += `<div class="two fields width85" id= "para${i}">`
value += '<div class="field">'
let placeholder_value='{{.i18n.Tr "repo.modelarts.train_job.parameter_value"}}'
let placeholder_name='{{.i18n.Tr "repo.modelarts.train_job.parameter_name"}}'
if(flag){
value +=`<input type="text" class="shipping_first-name" value="${paramsObject.label}">`
}else{
value +='<input type="text" class="shipping_first-name" required placeholder={{.i18n.Tr "repo.modelarts.train_job.parameter_name"}}>'
value +='<input type="text" class="shipping_first-name" required placeholder="' + placeholder_name+ '">'
}
value += '</div>'
value += '<div class="field">'
if(flag){
value +=`<input type="text" class="shipping_last-name" value="${paramsObject.value}">`
}else{
value +='<input type="text" class="shipping_last-name" required placeholder={{.i18n.Tr "repo.modelarts.train_job.parameter_value"}}>'
value +='<input type="text" class="shipping_last-name" required placeholder="' + placeholder_value + '">'
}
value += '</div>'
value += '<span><i class="trash icon"></i></span>'


+ 96
- 37
templates/repo/cloudbrain/trainjob/show.tmpl View File

@@ -272,7 +272,7 @@
class="cti-mgRight-sm">{{$.i18n.Tr "repo.modelarts.train_job.dura_time"}}:</span>
<span class="cti-mgRight-sm uc-accordionTitle-black"
id="{{.VersionName}}-duration-span">{{$.duration}}</span>
<span id="refresh-status" data-tooltip="刷新" style="cursor: pointer;" data-inverted="" data-version="{{.VersionName}}"><i
<span class="refresh-status" data-tooltip="刷新" style="cursor: pointer;" data-inverted="" data-version="{{.VersionName}}"><i
class="redo icon redo-color"></i></span>

</div>
@@ -286,10 +286,14 @@
<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="javascript:parseInfo()">{{$.i18n.Tr "repo.cloudbrain.runinfo"}}</a>
<a class="item" data-tab="third{{$k}}"
onclick="loadLog({{.VersionName}})">{{$.i18n.Tr "repo.modelarts.log"}}</a>

<a class="item log_bottom" data-tab="third{{$k}}"
data-version="{{.VersionName}}">{{$.i18n.Tr "repo.modelarts.log"}}</a>

<a class="item load-model-file" data-tab="four{{$k}}" data-gpu-flag="true" data-download-flag="{{$.canDownload}}" data-path="{{$.RepoLink}}/cloudbrain/train-job/{{.JobID}}/model_list" data-version="{{.VersionName}}" data-parents="" data-filename="" data-init="init" >{{$.i18n.Tr "repo.model_download"}}</a>
</div>
<div class="ui tab active" data-tab="first{{$k}}">
@@ -423,19 +427,7 @@
</td>
</tr>

<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "repo.modelarts.train_job.train_dataset"}}
</td>

<td class="ti-text-form-content">
<div class="text-span text-span-w">
{{range $m ,$n := $.datasetDownload}}
<a href="{{.RepositoryLink}}" target="_blank">{{.DatasetName}}</a>
{{end}}
</div>
</td>
</tr>

<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
@@ -464,6 +456,22 @@
</table>
</div>
</div>
<div style="clear:both">
<table style="border:none" class="ui fixed small stackable table">
<thead>
<tr><th style="color: #8a8e99;font-size:12px" class="three wide left aligned">{{$.i18n.Tr "dataset.file"}}</th>
</tr></thead>
<tbody>
{{range $m ,$n := $.datasetDownload}}
<tr>
<td style="word-wrap: break-word;word-break: break-all;"><a href="{{.RepositoryLink}}" target="_blank">{{.DatasetName}}</a></td>
</tr>
{{end}}

</tbody>
</table>
</div>
</div>

</div>
@@ -474,7 +482,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 log" id="log_state{{.VersionName}}"
style="height: 390px !important; overflow: auto;">
<input type="hidden" id="json_value" value="{{$.result.JobStatus.AppExitDiagnostics}}">
<input type="hidden" id="ExitDiagnostics" value="{{$.ExitDiagnostics}}">
@@ -488,18 +496,41 @@
</div>

<div class="ui tab" data-tab="third{{$k}}">
<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" id="log{{.VersionName}}"
<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>

@@ -553,7 +584,7 @@
<div id="newmodel">
<div class="ui modal second">
<div class="header" style="padding: 1rem;background-color: rgba(240, 240, 240, 100);">
<h4 id="model_header">导入新模型</h4>
<h4 id="model_header">{{.i18n.Tr "repo.model.manage.import_new_model"}}</h4>
</div>
<div class="content content-padding">
<form id="formId" method="POST" class="ui form">
@@ -563,26 +594,26 @@
<input type="hidden" name="trainTaskCreate" value="true">

<div class="required inline field">
<label>训练任务</label>
<label>{{.i18n.Tr "repo.model.manage.createtrainjob"}}</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>
</div>

<div class="required inline field" id="modelname">
<label>模型名称</label>
<label>{{.i18n.Tr "repo.model.manage.model_name"}}</label>
<input style="width: 45%;" id="name" name="Name" required maxlength="25"
onkeyup="this.value=this.value.replace(/[, ]/g,'')">
</div>
<div class="required inline field" id="verionname">
<label>模型版本</label>
<label>{{.i18n.Tr "repo.modelconvert.modelversion"}}</label>
<input style="width: 45%;" id="version" name="Version" value="" readonly required maxlength="255">
</div>
<div class="unite min_title inline field required">
<label>模型框架</label>
<label>{{.i18n.Tr "repo.model.manage.engine"}}</label>
<div class="ui dropdown selection search width70" id="choice_Engine">
<input type="hidden" id="Engine" name="Engine" required>
<div class="default text">选择模型框架</div>
<div class="default text">{{.i18n.Tr "repo.model.manage.select.engine"}}</div>
<i class="dropdown icon"></i>
<div class="menu" id="job-Engine">
<option class="active item" data-value="0">PyTorch</option>
@@ -597,7 +628,7 @@
</div>
<div class="unite min_title inline fields required">
<div class="field required">
<label for="modelSelectedFile">模型文件</label>
<label for="modelSelectedFile">{{.i18n.Tr "repo.model.manage.modelfile"}}</label>
</div>
<div class="thirteen wide field" style="position:relative">
<input id="modelSelectedFile" type="text" readonly required onclick="showMenu();" name="modelSelectedFile" >
@@ -607,12 +638,12 @@
</div>
</div>
<div class="inline field">
<label>模型标签</label>
<label>{{.i18n.Tr "repo.model.manage.modellabel"}}</label>
<input style="width: 83%;margin-left: 7px;" id="label" name="Label" maxlength="255"
placeholder='{{.i18n.Tr "repo.modelarts.train_job.label_place"}}'>
</div>
<div class="inline field">
<label for="description">模型描述</label>
<label for="description">{{.i18n.Tr "repo.model.manage.modeldesc"}}</label>
<textarea style="width: 83%;margin-left: 7px;" id="Description" name="Description" rows="3"
maxlength="255" placeholder='{{.i18n.Tr "repo.modelarts.train_job.new_place"}}'
onchange="this.value=this.value.substring(0, 255)"
@@ -702,7 +733,7 @@
hideMenu();
}
}
let dirKey="isOnlyDir--:&";
function loadSelectedModelFile(trainJob){
console.log("trainJob=" + trainJob);
$('#choice_file').dropdown('clear')
@@ -717,7 +748,7 @@
var zNodes=[];
var nodesMap={};
for (let i=0;i<n_length;i++){
parentNodeMap = nodesMap;
var parentNodeMap = nodesMap;
var fileSplits = data[i].FileName.split("/");
for(let j=0;j < fileSplits.length;j++){
if(fileSplits[j] == ""){
@@ -726,7 +757,22 @@
if(parentNodeMap[fileSplits[j]] == null){
parentNodeMap[fileSplits[j]] = {};
}
parentNodeMap = parentNodeMap[fileSplits[j]]
parentNodeMap = parentNodeMap[fileSplits[j]];
}
}
for (let i=0;i<n_length;i++){
var parentNodeMap = nodesMap;
var fileSplits = data[i].FileName.split("/");
for(let j=0;j < fileSplits.length;j++){
if(fileSplits[j] == ""){
if(data[i].FileName[data[i].FileName.length -1] =="/"){
if(Object.keys(parentNodeMap).length ==0){
parentNodeMap[dirKey]="true";
}
}
break;
}
parentNodeMap = parentNodeMap[fileSplits[j]];
}
}
convertToNode(zNodes,nodesMap);
@@ -746,12 +792,17 @@
node["name"] = keyList[i];
nodeList.push(node);
if(nodesMap[keyList[i]] != null && Object.keys(nodesMap[keyList[i]]).length >0){
node["children"]=[];
if(isFirst){
node["open"] = true;
isFirst= false;
if(nodesMap[keyList[i]][dirKey] != null){
node["open"] = false;
node["isParent"] = true;
}else{
node["children"]=[];
if(isFirst){
node["open"] = true;
isFirst= false;
}
convertToNode(node["children"],nodesMap[keyList[i]]);
}
convertToNode(node["children"],nodesMap[keyList[i]]);
}
}
}
@@ -850,7 +901,15 @@

function loadLog(version_name) {
document.getElementById("mask").style.display = "block"
$.get(`/api/v1/repos/${userName}/${repoPath}/cloudbrain/${taskID}/log?version_name=${version_name}&lines=50&order=asc`, (data) => {
let startLine = $('input[name=end_line]').val();
if(startLine==""){
startLine=0;
}
let endLine = $('input[name=end_line]').val();
if(endLine==""){
endLine = 50;
}
$.get(`/${userName}/${repoPath}/cloudbrain/train-job/${jobID}/get_log?endLine=${endLine}&startLine=${startLine}`, (data) => {
$('input[name=end_line]').val(data.EndLine)
$('input[name=start_line]').val(data.StartLine)
$(`#log_file${version_name}`).text(data.Content)


+ 83
- 61
templates/repo/datasets/index.tmpl View File

@@ -20,7 +20,6 @@
.wrapper {
display: flex;
overflow: hidden;
padding: 0 1rem;
}

.exp {
@@ -40,7 +39,8 @@
}

.exp:checked+.text .btn::after {
content:'{{$.i18n.Tr "org.fold"}}'
content:'{{$.i18n.Tr "org.fold"}}';
color: #3291f8;
}

.wrapper>.text {
@@ -80,7 +80,7 @@
margin-left: 20px;
font-size: 14px;
padding: 0 8px;
background: #3F51B5;
background-color: transparent;
line-height: 20px;
border-radius: 4px;
color: #fff;
@@ -89,7 +89,8 @@
}

.btn::after {
content:'{{$.i18n.Tr "org.unfold"}}'
content:'{{$.i18n.Tr "org.unfold"}}';
color: #3291f8;
}

.btn::before {
@@ -132,6 +133,15 @@
border: 5px solid transparent;
border-top-color: #c0c4cc;
}
.dataset-flavor-button{
display: flex;
align-items: center;
padding: 0.5rem;
border: 1px solid rgba(34,36,38,0.15);
border-top-right-radius: 0;
border-bottom-right-radius: 0;
box-shadow: none
}
</style>
<div class="repository">
{{template "repo/header" .}}
@@ -142,44 +152,59 @@
<div class="item" data-private="{{.IsPrivate}}" data-decompress-state="{{.DecompressState}}"></div>
{{end}}
</div>

<div id="dataset-base">
<div class="ui container">
<div class="ui mobile reversed stackable grid">
<div class="row">
<div class="column thirteen wide">
<h2 class="nowrap">{{.dataset.Title}}</h2>
<div class="ui blue small menu compact selectcloudbrain">
<a class="active item" href="{{.RepoLink}}/datasets">{{$.i18n.Tr "dataset.current_dataset"}}</a>
<a class="item" href="{{.RepoLink}}/datasets/reference_datasets">{{$.i18n.Tr "dataset.linked_dataset"}}</a>
</div>
<div class="column three wide right aligned">
<span style="display: flex;align-items: center;justify-content: flex-end;height: 36px;">
{{if $.IsSigned}}
<div style="line-height: 1;margin-right: 4px;margin-bottom: -2px;padding: 0 10px;"
@click="postStar({{.dataset.ID}},'{{.Link}}')">
<svg width="1.4em" height="1.4em" viewBox="0 0 32 32" class="heart-stroke"
:class='{stars_active:star_active}'>
<path
d="M4.4 6.54c-1.761 1.643-2.6 3.793-2.36 6.056.24 2.263 1.507 4.521 3.663 6.534a29110.9 29110.9 0 0010.296 9.633l10.297-9.633c2.157-2.013 3.424-4.273 3.664-6.536.24-2.264-.599-4.412-2.36-6.056-1.73-1.613-3.84-2.29-6.097-1.955-1.689.25-3.454 1.078-5.105 2.394l-.4.319-.398-.319c-1.649-1.316-3.414-2.143-5.105-2.394a7.612 7.612 0 00-1.113-.081c-1.838 0-3.541.694-4.983 2.038z">
</path>
</svg>
</div>
<span style="line-height: 1;">${num_stars}</span>
{{else}}
<div style="line-height: 1;margin-right: 4px;margin-bottom: -2px;padding: 0 10px;">
<svg width="1.4em" height="1.4em" viewBox="0 0 32 32" class="heart-stroke"
:class='{stars_active:star_active}'>
<path
d="M4.4 6.54c-1.761 1.643-2.6 3.793-2.36 6.056.24 2.263 1.507 4.521 3.663 6.534a29110.9 29110.9 0 0010.296 9.633l10.297-9.633c2.157-2.013 3.424-4.273 3.664-6.536.24-2.264-.599-4.412-2.36-6.056-1.73-1.613-3.84-2.29-6.097-1.955-1.689.25-3.454 1.078-5.105 2.394l-.4.319-.398-.319c-1.649-1.316-3.414-2.143-5.105-2.394a7.612 7.612 0 00-1.113-.081c-1.838 0-3.541.694-4.983 2.038z">
</path>
</svg>
</div>
<span style="line-height: 1;">${num_stars}</span>
{{end}}
<a style="margin-left:30px;" href="{{.RepoLink}}/datasets/edit/{{.dataset.ID}}"
class="ui primary basic mini {{if not $.CanWrite}} disabled {{end}} button">{{.i18n.Tr "repo.modelarts.modify"}}</a>
</span>
</div>
<div class="row" style="align-items: center;">
<h2 class="nowrap" style="margin: 0;">{{.dataset.Title}}</h2>
<!-- border-top-right-radius: 0;
border-bottom-right-radius: 0; -->
<div style="margin-left: 1.5rem;">
{{if $.IsSigned}}
<button v-if="star_active" class="ui mini basic button" style="display: flex;align-items: center;padding: 0.5rem;border: #888888;border-top-right-radius: 0;border-bottom-right-radius: 0;margin-right: -1px;" @click="postStar({{.dataset.ID}},'{{.Link}}')">
<i class="ri-heart-fill" style="color: #FA8C16;"></i>
<span style="margin-left: 0.3rem;font-size: 0.7rem;">{{$.i18n.Tr "dataset.unfavorite"}}</span>
</button>
<button v-else class="ui mini basic button" style="display: flex;align-items: center;padding:0.5rem;border: #888888;border-top-right-radius: 0;border-bottom-right-radius: 0;margin-right: -1px;" @click="postStar({{.dataset.ID}},'{{.Link}}')">
<i class="ri-heart-line" ></i>
<span style="margin-left: 0.3rem;font-size: 0.7rem;">{{$.i18n.Tr "dataset.favorite"}}</span>
</button>
{{else}}
<button v-if="star_active" class="ui mini basic button" style="display: flex;align-items: center;padding: 0.5rem;border: #888888;border-top-right-radius: 0;border-bottom-right-radius: 0;margin-right: -1px;">
<i class="ri-heart-fill" ></i>
<span style="margin-left: 0.3rem;font-size: 0.7rem;">{{$.i18n.Tr "dataset.unfavorite"}}</span>
</button>
<button v-else class="ui mini basic button" style="display: flex;align-items: center;padding:0.5rem;border: #888888;border-top-right-radius: 0;border-bottom-right-radius: 0;margin-right: -1px;">
<i class="ri-heart-line" style="color: #FA8C16;"></i>
<span style="margin-left: 0.3rem;font-size: 0.7rem;">{{$.i18n.Tr "dataset.favorite"}}</span>
</button>
{{end}}
</div>
<a class="ui mini basic button" style="display: flex;align-items: center;padding: 0.5rem;border: #888888;border-top-left-radius: 0;border-bottom-left-radius: 0;">
${num_stars}
</a>
<a style="margin-left:15px;padding: 0.5rem 1.5rem;" href="{{.RepoLink}}/datasets/edit/{{.dataset.ID}}" class="ui primary basic mini {{if not $.CanWrite}} disabled {{end}} button">{{.i18n.Tr "repo.modelarts.modify"}}</a>
</div>
{{if .dataset.Description}}
<div class="row" style="padding: 0;">
<div class="wrapper">
<input id="exp1" class="exp" type="checkbox">
<div class="text">
<label class="btn" for="exp1"></label>
{{.dataset.Description}}
</div>
</div>
</div>
{{end}}
<div class="row" style="align-items: center;">
{{if or (.dataset.Category) (.dataset.Task) (.dataset.License)}}
<div class="column thirteen wide">
<div class="column ten wide" style="padding:0">
{{if .dataset.Category}}
{{$category := .dataset.Category}}
<a class="ui repo-topic label topic"
@@ -196,21 +221,7 @@
{{end}}
</div>
{{end}}
</div>
{{if .dataset.Description}}
<div class="row" style="padding-top: 0;">
<div class=" wrapper">
<input id="exp1" class="exp" type="checkbox">
<div class="text">
<label class="btn" for="exp1"></label>
{{.dataset.Description}}
</div>
</div>
</div>
{{end}}
<div class="row">
<div class="column ten wide"></div>
<div class="column six wide right aligned">
<div class="column six wide right aligned" style="padding:0">
<el-select v-model="datasetType" style="width: 40%;" size="small" @change="changeDatasetType">
<i slot="prefix" style="display: inline-block;color: #101010;"
class="el-input__icon ri-archive-drawer-line"></i>
@@ -222,7 +233,7 @@
@click="gotoUpload('{{.RepoLink}}',{{.dataset.ID}})">{{$.i18n.Tr "dataset.dataset_upload"}}</el-button>
</div>
</div>
<div class="row">
<div class="row" style="padding-top: 0;">
<div class="ui sixteen wide column dataset">
<div class="ui grid stackable" style="background: #f0f0f0;;">
<div class="row">
@@ -387,16 +398,27 @@
</div>
</div>
{{else}}
<div class="ui placeholder segment bgtask-none">
<div class="ui icon header bgtask-header-pic"></div>
<div class="bgtask-content-header">{{.i18n.Tr "dataset.dataset_no_create"}}</div>
{{if $.CanWrite}}
<a class="ui green button" href="{{.RepoLink}}/datasets/create">{{.i18n.Tr "dataset.create_new_dataset"}}</a>
{{end}}
<div class="bgtask-content">
<div class="bgtask-content-txt">{{.i18n.Tr "dataset.dataset_explain"}}</div>
<div class="bgtask-content-txt">{{.i18n.Tr "dataset.dataset_instructions_for_use"}}<a
href="https://git.openi.org.cn/zeizei/OpenI_Learning">{{.i18n.Tr "dataset.dataset_camp_course"}}</a></div>
<div class="ui container">
<div class="ui stackable grid">
<div class="row" style="justify-content: space-between">
<div class="ui blue small menu compact selectcloudbrain">
<a class="active item" href="{{.RepoLink}}/datasets">{{$.i18n.Tr "dataset.current_dataset"}}</a>
<a class="item" href="{{.RepoLink}}/datasets/reference_datasets">{{$.i18n.Tr "dataset.linked_dataset"}}</a>
</div>
{{if $.CanWrite}}
<a class="ui green button" href="{{.RepoLink}}/datasets/create">{{$.i18n.Tr "new_dataset"}}</a>
{{end}}
</div>
</div>
<div class="ui placeholder segment bgtask-none">
<div class="ui icon header bgtask-header-pic"></div>
<div class="bgtask-content-header">{{.i18n.Tr "dataset.dataset_no_create"}}</div>
<div class="bgtask-content">
<div class="bgtask-content-txt">{{.i18n.Tr "dataset.dataset_explain"}}</div>
<div class="bgtask-content-txt">{{.i18n.Tr "dataset.dataset_instructions_for_use"}}<a
href="https://git.openi.org.cn/zeizei/OpenI_Learning">{{.i18n.Tr "dataset.dataset_camp_course"}}</a></div>
</div>
</div>
</div>
{{end}}


+ 8
- 0
templates/repo/datasets/reference.tmpl View File

@@ -0,0 +1,8 @@
{{template "base/head" .}}

<div class="repository">
{{template "repo/header" .}}
<div class="reference-dataset" data-repolink="{{.RepoLink}}" data-canwrite="{{.CanWrite}}" data-is-sign="{{$.IsSigned}}" data-max-reference-num="{{.MaxReferenceDatasetNum}}" data-address="{{IsShowDataSetOfCurrentRepo $.Repository.ID}}"></div>
<div id="reference-dataset"></div>
</div>
{{template "base/footer" .}}

+ 2
- 1
templates/repo/debugjob/index.tmpl View File

@@ -235,7 +235,8 @@
<div class="two wide column text center">
<!-- 任务计算资源 -->
<span style="font-size: 12px;margin-left: 0.4rem;"
class="">{{.ComputeResource}}</span>
class="">
{{.ComputeResource}}</span>
</div>
<div class="one wide column text center">
{{if .User.Name}}


+ 17
- 7
templates/repo/grampus/trainjob/gpu/new.tmpl View File

@@ -66,7 +66,7 @@
</h4>
<div class="ui attached segment">
<!-- equal width -->
<form class="ui form" action="{{.Link}}" method="post">
<form id="form_id" class="ui form" action="{{.Link}}" method="post">
{{.CsrfTokenHtml}}
<input type="hidden" name="action" value="update">
<input type="hidden" id="ai_engine_name" name="engine_name" value="">
@@ -106,6 +106,10 @@
Ascend NPU</a>
</div>
{{template "custom/wait_count_train" Dict "ctx" $}}
<div style="display: flex;align-items: center;margin-left: 155px;margin-top: 0.5rem;">
<i class="ri-error-warning-line" style="color: #f2711c;margin-right: 0.5rem;"></i>
<span style="color: #888;font-size: 12px;">{{.i18n.Tr "cloudbrain.new_train_gpu_tooltips" "/tmp/code" "/tmp/dataset" "/tmp/output" | Safe}}</span>
</div>
</div>
<div class="required min_title inline field">
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.job_name"}}</label>
@@ -160,12 +164,12 @@
<span>
<i class="question circle icon link" data-content={{.i18n.Tr "repo.modelarts.train_job.boot_file_helper"}} data-position="right center" data-variation="mini"></i>
</span>
<a href="https://git.openi.org.cn/OpenIOSSG/MNIST_PytorchExample_GPU/src/branch/master/train_for_c2net.py" target="_blank">查看样例</a>
<a href="https://git.openi.org.cn/OpenIOSSG/MNIST_PytorchExample_GPU/src/branch/master/train_for_c2net.py" target="_blank">{{.i18n.Tr "cloudbrain.view_sample"}}</a>
</div>

{{template "custom/select_dataset_train" .}}
<span class="tooltips" style="margin-left: 11.5rem;margin-bottom: 2rem;">{{.i18n.Tr "repo.grampus.gpu_dataset_path_rule"}}</span>
<span class="tooltips" style="margin-left: 11.5rem;margin-bottom: 1rem;"></span>
<div class="inline min_title field">
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.run_parameter"}}</label>
<span id="add_run_para" style="margin-left: 0.5rem;cursor:pointer;color: rgba(3, 102, 214, 100);font-size: 14px;line-height: 26px;font-family: SourceHanSansSC-medium;"><i class="plus square outline icon"></i>{{.i18n.Tr "repo.modelarts.train_job.add_run_parameter"}}</span>
@@ -214,8 +218,12 @@
{{template "base/footer" .}}

<script>
//let url_href = window.location.pathname.split('create')[0]
//$(".ui.button").attr('href',url_href)
let form = document.getElementById('form_id');
let createFlag = false
form.onsubmit = function (e) {
if(createFlag) return false
createFlag = true
}
$('select.dropdown')
.dropdown();

@@ -235,17 +243,19 @@
let value = ''
value += `<div class="two fields width85" id= "para${i}">`
value += '<div class="field">'
let placeholder_value='{{.i18n.Tr "repo.modelarts.train_job.parameter_value"}}'
let placeholder_name='{{.i18n.Tr "repo.modelarts.train_job.parameter_name"}}'
if(flag){
value +=`<input type="text" class="shipping_first-name" value="${paramsObject.label}">`
}else{
value +='<input type="text" class="shipping_first-name" required placeholder={{.i18n.Tr "repo.modelarts.train_job.parameter_name"}}>'
value +='<input type="text" class="shipping_first-name" required placeholder="' + placeholder_name+ '">'
}
value += '</div>'
value += '<div class="field">'
if(flag){
value +=`<input type="text" class="shipping_last-name" value="${paramsObject.value}">`
}else{
value +='<input type="text" class="shipping_last-name" required placeholder={{.i18n.Tr "repo.modelarts.train_job.parameter_value"}}>'
value +='<input type="text" class="shipping_last-name" required placeholder="' + placeholder_value+ '">'
}
value += '</div>'
value += '<span><i class="trash icon"></i></span>'


+ 16
- 5
templates/repo/grampus/trainjob/npu/new.tmpl View File

@@ -61,7 +61,7 @@
</h4>
<div class="ui attached segment">
<!-- equal width -->
<form class="ui form" action="{{.Link}}" method="post">
<form id="form_id" class="ui form" action="{{.Link}}" method="post">
{{.CsrfTokenHtml}}
<input type="hidden" name="action" value="update">
<input type="hidden" id="ai_engine_name" name="engine_name" value="">
@@ -100,6 +100,10 @@
Ascend NPU</a>
</div>
{{template "custom/wait_count_train" Dict "ctx" $}}
<div style="display: flex;align-items: center;margin-left: 155px;margin-top: 0.5rem;">
<i class="ri-error-warning-line" style="color: #f2711c;margin-right: 0.5rem;"></i>
<span style="color: #888;font-size: 12px;">{{.i18n.Tr "cloudbrain.new_train_gpu_tooltips" "/cache/code" "/cache/dataset" "/cache/output" | Safe}}</span>
</div>
</div>
<div class="required min_title inline field">
@@ -177,7 +181,7 @@
</div>
{{template "custom/select_dataset_train" .}}
<span class="tooltips" style="margin-left: 11.5rem;margin-bottom: 2rem;">{{.i18n.Tr "repo.grampus.dataset_path_rule"}}</span>
<span class="tooltips" style="margin-left: 11.5rem;margin-bottom: 1rem;"></span>
<div class="inline min_title field">
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.run_parameter"}}</label>
<span id="add_run_para" style="margin-left: 0.5rem;cursor:pointer;color: rgba(3, 102, 214, 100);font-size: 14px;line-height: 26px;font-family: SourceHanSansSC-medium;"><i class="plus square outline icon"></i>{{.i18n.Tr "repo.modelarts.train_job.add_run_parameter"}}</span>
@@ -240,7 +244,12 @@
{{template "base/footer" .}}

<script>
let form = document.getElementById('form_id');
let createFlag = false
form.onsubmit = function (e) {
if(createFlag) return false
createFlag = true
}
$('select.dropdown')
.dropdown();

@@ -260,17 +269,19 @@
let value = ''
value += `<div class="two fields width85" id= "para${i}">`
value += '<div class="field">'
let placeholder_value='{{.i18n.Tr "repo.modelarts.train_job.parameter_value"}}'
let placeholder_name='{{.i18n.Tr "repo.modelarts.train_job.parameter_name"}}'
if(flag){
value +=`<input type="text" class="shipping_first-name" value="${paramsObject.label}">`
}else{
value +='<input type="text" class="shipping_first-name" required placeholder={{.i18n.Tr "repo.modelarts.train_job.parameter_name"}}>'
value +='<input type="text" class="shipping_first-name" required placeholder="' + placeholder_name+ '">'
}
value += '</div>'
value += '<div class="field">'
if(flag){
value +=`<input type="text" class="shipping_last-name" value="${paramsObject.value}">`
}else{
value +='<input type="text" class="shipping_last-name" required placeholder={{.i18n.Tr "repo.modelarts.train_job.parameter_value"}}>'
value +='<input type="text" class="shipping_last-name" required placeholder="' + placeholder_value+ '">'
}
value += '</div>'
value += '<span><i class="trash icon"></i></span>'


+ 42
- 22
templates/repo/grampus/trainjob/show.tmpl View File

@@ -257,7 +257,7 @@
class="cti-mgRight-sm">{{$.i18n.Tr "repo.modelarts.train_job.dura_time"}}:</span>
<span class="cti-mgRight-sm uc-accordionTitle-black"
id="{{.VersionName}}-duration-span">{{.TrainJobDuration}}</span>
<span id="refresh-status" data-tooltip="刷新" style="cursor: pointer;" data-inverted="" data-version="{{.VersionName}}">
<span class="refresh-status" data-tooltip="刷新" style="cursor: pointer;" data-inverted="" data-version="{{.VersionName}}">
<i class="redo icon redo-color"></i>
</span>

@@ -470,11 +470,11 @@
<div class="ui tab" data-tab="second{{$k}}">
<div style="position: relative;">
<span>
<a title="滚动到顶部" style="position: absolute; right: -32px;cursor: pointer;"
<a title="{{$.i18n.Tr "repo.log_scroll_start"}}" 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">
<a title="滚动到底部" style="position: absolute; bottom: 10px;right: -32px;cursor: pointer;"
<span class="log-info-{{.VersionName}}">
<a title="{{$.i18n.Tr "repo.log_scroll_end"}}" style="position: absolute; bottom: 10px;right: -32px;cursor: pointer;"
class="log_bottom" data-version="{{.VersionName}}"><i
class="icon-to-bottom"></i></a>
</span>
@@ -541,7 +541,7 @@
<div id="newmodel">
<div class="ui modal second">
<div class="header" style="padding: 1rem;background-color: rgba(240, 240, 240, 100);">
<h4 id="model_header">导入新模型</h4>
<h4 id="model_header">{{.i18n.Tr "repo.model.manage.import_new_model"}}</h4>
</div>
<div class="content content-padding">
<form id="formId" method="POST" class="ui form">
@@ -551,26 +551,26 @@
<input type="hidden" name="trainTaskCreate" value="true">

<div class="required inline field">
<label>训练任务</label>
<label>{{.i18n.Tr "repo.model.manage.createtrainjob"}}</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>
</div>

<div class="required inline field" id="modelname">
<label>模型名称</label>
<label>{{.i18n.Tr "repo.model.manage.model_name"}}</label>
<input style="width: 45%;" id="name" name="Name" required maxlength="25"
onkeyup="this.value=this.value.replace(/[, ]/g,'')">
</div>
<div class="required inline field" id="verionname">
<label>模型版本</label>
<label>{{.i18n.Tr "repo.modelconvert.modelversion"}}</label>
<input style="width: 45%;" id="version" name="Version" value="" readonly required maxlength="255">
</div>
<div class="unite min_title inline field required">
<label>模型框架</label>
<label>{{.i18n.Tr "repo.model.manage.engine"}}</label>
<div class="ui dropdown selection search width70" id="choice_Engine">
<input type="hidden" id="Engine" name="Engine" required>
<div class="default text">选择模型框架</div>
<div class="default text">{{.i18n.Tr "repo.model.manage.select.engine"}}</div>
<i class="dropdown icon"></i>
<div class="menu" id="job-Engine">
<option class="active item" data-value="0">PyTorch</option>
@@ -586,7 +586,7 @@
</div>
<div class="unite min_title inline fields required">
<div class="field required">
<label for="modelSelectedFile">模型文件</label>
<label for="modelSelectedFile">{{.i18n.Tr "repo.model.manage.modelfile"}}</label>
</div>
<div class="thirteen wide field" style="position:relative">
<input id="modelSelectedFile" type="text" readonly required onclick="showMenu();" name="modelSelectedFile" >
@@ -596,12 +596,12 @@
</div>
</div>
<div class="inline field">
<label>模型标签</label>
<label>{{.i18n.Tr "repo.model.manage.modellabel"}}</label>
<input style="width: 83%;margin-left: 7px;" id="label" name="Label" maxlength="255"
placeholder='{{.i18n.Tr "repo.modelarts.train_job.label_place"}}'>
</div>
<div class="inline field">
<label for="description">模型描述</label>
<label for="description">{{.i18n.Tr "repo.model.manage.modeldesc"}}</label>
<textarea style="width: 83%;margin-left: 7px;" id="Description" name="Description" rows="3"
maxlength="255" placeholder='{{.i18n.Tr "repo.modelarts.train_job.new_place"}}'
onchange="this.value=this.value.substring(0, 255)"
@@ -691,7 +691,7 @@
hideMenu();
}
}
let dirKey="isOnlyDir--:&";
function loadSelectedModelFile(trainJob){
console.log("trainJob=" + trainJob);
$('#choice_file').dropdown('clear')
@@ -714,7 +714,7 @@
var zNodes=[];
var nodesMap={};
for (let i=0;i<n_length;i++){
parentNodeMap = nodesMap;
var parentNodeMap = nodesMap;
var fileSplits = data[i].FileName.split("/");
for(let j=0;j < fileSplits.length;j++){
if(fileSplits[j] == ""){
@@ -723,7 +723,22 @@
if(parentNodeMap[fileSplits[j]] == null){
parentNodeMap[fileSplits[j]] = {};
}
parentNodeMap = parentNodeMap[fileSplits[j]]
parentNodeMap = parentNodeMap[fileSplits[j]];
}
}
for (let i=0;i<n_length;i++){
var parentNodeMap = nodesMap;
var fileSplits = data[i].FileName.split("/");
for(let j=0;j < fileSplits.length;j++){
if(fileSplits[j] == ""){
if(data[i].FileName[data[i].FileName.length -1] =="/"){
if(Object.keys(parentNodeMap).length ==0){
parentNodeMap[dirKey]="true";
}
}
break;
}
parentNodeMap = parentNodeMap[fileSplits[j]];
}
}
convertToNode(zNodes,nodesMap);
@@ -743,12 +758,17 @@
node["name"] = keyList[i];
nodeList.push(node);
if(nodesMap[keyList[i]] != null && Object.keys(nodesMap[keyList[i]]).length >0){
node["children"]=[];
if(isFirst){
node["open"] = true;
isFirst= false;
if(nodesMap[keyList[i]][dirKey] != null){
node["open"] = false;
node["isParent"] = true;
}else{
node["children"]=[];
if(isFirst){
node["open"] = true;
isFirst= false;
}
convertToNode(node["children"],nodesMap[keyList[i]]);
}
convertToNode(node["children"],nodesMap[keyList[i]]);
}
}
}
@@ -773,7 +793,7 @@
}
if (srcEngine == 'mindspore') {
$('#choice_Engine .default.text').text("MindSpore");
$('#choice_Engine input[name="Engine"]').val(1)
$('#choice_Engine input[name="Engine"]').val(2)
}
}
}else{


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

@@ -138,7 +138,7 @@
{{end}}

{{if .Permission.CanRead $.UnitTypeDatasets}}
<a class="{{if .PageIsDataset}}active{{end}} item" href="{{.RepoLink}}/datasets">
<a class="{{if .PageIsDataset}}active{{end}} item" id="header-dataset" href="{{.RepoLink}}{{if IsShowDataSetOfCurrentRepo $.Repository.ID}}/datasets{{else}}/datasets/reference_datasets{{end}}">
<svg class="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16"><path fill="none" d="M0 0h24v24H0z"/><path d="M20.083 15.2l1.202.721a.5.5 0 0 1 0 .858l-8.77 5.262a1 1 0 0 1-1.03 0l-8.77-5.262a.5.5 0 0 1 0-.858l1.202-.721L12 20.05l8.083-4.85zm0-4.7l1.202.721a.5.5 0 0 1 0 .858L12 17.65l-9.285-5.571a.5.5 0 0 1 0-.858l1.202-.721L12 15.35l8.083-4.85zm-7.569-9.191l8.771 5.262a.5.5 0 0 1 0 .858L12 13 2.715 7.429a.5.5 0 0 1 0-.858l8.77-5.262a1 1 0 0 1 1.03 0zM12 3.332L5.887 7 12 10.668 18.113 7 12 3.332z"/></svg>
{{.i18n.Tr "datasets"}}
</a>


+ 22
- 7
templates/repo/modelarts/inferencejob/new.tmpl View File

@@ -40,12 +40,13 @@
{{template "repo/header" .}}
<div class="ui container">
{{template "base/alert" .}}
<div class="cloudbrain-type" style="display: none;" data-cloudbrain-type="1" data-repo-link="{{.RepoLink}}"></div>
<h4 class="ui top attached header">
{{.i18n.Tr "repo.modelarts.train_job.new_infer"}}
</h4>
<div class="ui attached segment">
<!-- equal width -->
<form class="ui form" action="{{.Link}}" method="post">
<form id="form_id" class="ui form" action="{{.Link}}" method="post">
{{.CsrfTokenHtml}}
<input type="hidden" name="action" value="update">
<input type="hidden" id="ai_engine_name" name="engine_names" value="">
@@ -83,6 +84,10 @@
Ascend NPU</a>
</div>
{{template "custom/wait_count_train" Dict "ctx" $}}
<div style="display: flex;align-items: center;margin-left: 155px;margin-top: 0.5rem;">
<i class="ri-error-warning-line" style="color: #f2711c;margin-right: 0.5rem;"></i>
<span style="color: #888;font-size: 12px;">{{.i18n.Tr "cloudbrain.infer_dataset_path_rule" | Safe}}</span>
</div>
</div>
<div class="required min_title inline field">
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.job_name"}}</label>
@@ -191,9 +196,12 @@
{{end}}
</select>
</div>
<!-- 数据集 -->
{{template "custom/select_dataset_train" .}}
<span class="tooltips" style="margin-left: 11.5rem;margin-bottom: 2rem;">{{.i18n.Tr "cloudbrain.dataset_path_rule"}}</span>
<!-- 数据集 -->
<div id="select-multi-dataset">

</div>
<span class="tooltips" style="margin-left: 11.5rem;margin-bottom: 1rem;"></span>
<div class="inline min_title field required">
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.start_file"}}</label>
{{if .bootFile}}
@@ -269,7 +277,6 @@
<div class="ui labeled input" style="width: 5%;">
<input style="border-radius: 0;text-align: center;" name="work_server_number" id="trainjob_work_server_num" tabindex="3" autofocus required maxlength="255" value="1" readonly>
</div>
<span class="tooltips" style="margin-left: 11.5rem;display: block;">{{.i18n.Tr "cloudbrain.inference_output_path_rule"}}</span>
</div>
<!-- 表单操作 -->
<div class="inline min_title field">
@@ -287,6 +294,12 @@
{{template "base/footer" .}}

<script>
let form = document.getElementById('form_id');
let createFlag = false
form.onsubmit = function (e) {
if(createFlag) return false
createFlag = true
}
const RepoLink = {{.RepoLink}}
const url_href = window.location.pathname.split('create')[0]
let nameMap,nameList
@@ -396,12 +409,14 @@

// 参数增加、删除、修改、保存
function Add_parameter(i){
let placeholder_value='{{.i18n.Tr "repo.modelarts.train_job.parameter_value"}}'
let placeholder_name='{{.i18n.Tr "repo.modelarts.train_job.parameter_name"}}'
value = '<div class="two fields width85" id= "para'+ i +'">' +
'<div class="field">' +
'<input type="text" name="shipping_first-name" required placeholder={{.i18n.Tr "repo.modelarts.train_job.parameter_name"}}> ' +
'<input type="text" name="shipping_first-name" required placeholder="' + placeholder_name+ '">' +
'</div> ' +
'<div class="field"> ' +
'<input type="text" name="shipping_last-name" required placeholder={{.i18n.Tr "repo.modelarts.train_job.parameter_value"}}>' +
'<input type="text" name="shipping_last-name" required placeholder="' + placeholder_value + '">' +
'</div>'+
'<span>' +
'<i class="trash icon">' +


+ 21
- 17
templates/repo/modelarts/inferencejob/show.tmpl View File

@@ -199,7 +199,7 @@ td, th {
class="cti-mgRight-sm">{{$.i18n.Tr "repo.modelarts.train_job.dura_time"}}:</span>
<span class="cti-mgRight-sm uc-accordionTitle-black"
id="{{.VersionName}}-duration-span">{{.TrainJobDuration}}</span>
<span id="refresh-status" data-tooltip="刷新" style="cursor: pointer;" data-inverted="" data-version="{{.VersionName}}"><i
<span class="refresh-status" data-tooltip="刷新" style="cursor: pointer;" data-inverted="" data-version="{{.VersionName}}"><i
class="redo icon redo-color"></i></span>

</div>
@@ -217,7 +217,7 @@ td, th {
<a class="item load-model-file" data-tab="third" data-download-flag="{{$.canDownload}}" data-path="{{$.RepoLink}}/modelarts/inference-job/{{.JobID}}/result_list" data-version="{{.VersionName}}" data-parents="" data-filename="" data-init="init" >{{$.i18n.Tr "repo.model_download"}}</a>
</div>

<div class="ui tab active" data-tab="first" style="height:400px">
<div class="ui tab active" data-tab="first">
<div style="padding-top: 10px;">
<div class="tab_2_content">
<div class="ac-grid ac-grid-col2">
@@ -314,7 +314,7 @@ td, th {
</tr>
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
创建人
{{$.i18n.Tr "repo.cloudbrain_creator"}}
</td>

<td class="ti-text-form-content">
@@ -402,19 +402,7 @@ td, th {
</div>
</td>
</tr>
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "repo.modelarts.infer_dataset"}}
</td>

<td class="ti-text-form-content">
<div class="text-span text-span-w">
{{range $m ,$n := $.datasetDownload}}
<a href="{{.RepositoryLink}}" target="_blank">{{.DatasetName}}</a>
{{end}}
</div>
</td>
</tr>
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80" >
{{$.i18n.Tr "repo.modelarts.train_job.run_parameter"}}
@@ -445,6 +433,22 @@ td, th {
</table>
</div>
</div>
<div style="clear:both">
<table style="border:none" class="ui fixed small stackable table">
<thead>
<tr><th style="color: #8a8e99;font-size:12px" class="three wide left aligned">{{$.i18n.Tr "dataset.file"}}</th>
</tr></thead>
<tbody>
{{range $m ,$n := $.datasetDownload}}
<tr>
<td style="word-wrap: break-word;word-break: break-all;"><a href="{{.RepositoryLink}}" target="_blank">{{.DatasetName}}</a></td>
</tr>
{{end}}

</tbody>
</table>
</div>
</div>

</div>
@@ -465,7 +469,7 @@ td, th {
<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">
<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>


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

@@ -123,11 +123,10 @@
})
}
validate();
let createFlag = false
form.onsubmit = function(e){
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)
if(!flag){
@@ -136,11 +135,10 @@
$('#messageInfo p').text(str)
return false
}

let min_value_task = value_task.toLowerCase()

$("input[name='display_job_name']").attr("value",min_value_task)
document.getElementById("mask").style.display = "block"
createFlag = true

}
// 点击按钮后遮罩层显示


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

@@ -248,7 +248,7 @@
class="cti-mgRight-sm">{{$.i18n.Tr "repo.modelarts.train_job.dura_time"}}:</span>
<span class="cti-mgRight-sm uc-accordionTitle-black"
id="{{.VersionName}}-duration-span">{{$.duration}}</span>
<span id="refresh-status" data-tooltip="刷新" style="cursor: pointer;" data-inverted="" data-version="{{.VersionName}}">
<span class="refresh-status" data-tooltip="刷新" style="cursor: pointer;" data-inverted="" data-version="{{.VersionName}}">
<i class="redo icon redo-color"></i>
</span>
</div>
@@ -432,16 +432,16 @@
<div style="clear:both">
<table style="border:none" class="ui fixed small stackable table">
<thead>
<tr><th style="color: #8a8e99;font-size:12px" class="three wide center aligned">数据集文件</th>
<th style="color: #8a8e99;font-size:12px"class="eleven wide">数据集下载地址</th>
<th style="color: #8a8e99;font-size:12px" class="two wide center aligned">操作</th>
<tr><th style="color: #8a8e99;font-size:12px" class="three wide center aligned">{{$.i18n.Tr "dataset.file"}}</th>
<th style="color: #8a8e99;font-size:12px"class="eleven wide">{{$.i18n.Tr "dataset.download_url"}}</th>
<th style="color: #8a8e99;font-size:12px" class="two wide center aligned">{{$.i18n.Tr "dataset.download_oper"}}</th>
</tr></thead>
<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;">{{.DatasetDownloadLink}}</td>
<td class="center aligned"><a class="ui poping up clipboard" id="clipboard-btn" 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}}">复制链接</a></td>
<td class="center aligned"><a class="ui poping up clipboard" id="clipboard-btn" 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>
{{end}}
</tbody>


+ 6
- 4
templates/repo/modelarts/trainjob/edit_para.tmpl View File

@@ -76,10 +76,10 @@
{{range .para}}
<div class="two fields">
<div class="field">
<input type="text" name="shipping_first-name" placeholder={{.i18n.Tr "repo.modelarts.train_job.parameter_name"}}>
<input type="text" name="shipping_first-name" placeholder="{{.i18n.Tr "repo.modelarts.train_job.parameter_name"}}">
</div>
<div class="field">
<input type="text" name="shipping_last-name" placeholder={{.i18n.Tr "repo.modelarts.train_job.parameter_value"}}>
<input type="text" name="shipping_last-name" placeholder="{{.i18n.Tr "repo.modelarts.train_job.parameter_value"}}">
</div>
<span>
<i class="trash icon">
@@ -151,12 +151,14 @@

// 参数增加、删除、修改、保存
function Add_parameter(){
let placeholder_value='{{.i18n.Tr "repo.modelarts.train_job.parameter_value"}}'
let placeholder_name='{{.i18n.Tr "repo.modelarts.train_job.parameter_name"}}'
value = '<div class="two fields">' +
'<div class="field">' +
'<input type="text" name="shipping_first-name" placeholder={{.i18n.Tr "repo.modelarts.train_job.parameter_name"}}> ' +
'<input type="text" name="shipping_first-name" placeholder="' + placeholder_name+ '">' +
'</div> ' +
'<div class="field"> ' +
'<input type="text" name="shipping_last-name" placeholder={{.i18n.Tr "repo.modelarts.train_job.parameter_value"}}>' +
'<input type="text" name="shipping_last-name" placeholder="' + placeholder_value+ '">' +
'</div>'+
'<span>' +
'<i class="trash icon">' +


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

@@ -95,7 +95,7 @@
<span>{{$.i18n.Tr "repo.cloudbrain_status_runtime"}}</span>
</div>
<div class="two wide column text center padding0">
<span>{{$.i18n.Tr "repo.modelarts.computing_resources"}}</span>
<span>{{$.i18n.Tr "repo.modelarts.cluster.computing_resources"}}</span>
</div>
<div class="one wide column text center padding0">
<span>{{$.i18n.Tr "repo.cloudbrain_creator"}}</span>
@@ -137,7 +137,13 @@
</div>
<!-- 计算资源 -->
<div class="two wide column text center padding0">
<span style="font-size: 12px;">{{.ComputeResource}}</span>
<span style="font-size: 12px;">
{{if eq .Cloudbrain.Type 2}}
{{$.i18n.Tr "cloudbrain.resource_cluster_c2net_simple"}}
{{else}}
{{$.i18n.Tr "cloudbrain.resource_cluster_openi_simple"}}
{{end}}
{{.ComputeResource}}</span>
</div>
<!-- 创建者 -->
<div class="one wide column text center padding0">


+ 16
- 19
templates/repo/modelarts/trainjob/new.tmpl View File

@@ -69,7 +69,7 @@
</h4>
<div class="ui attached segment">
<!-- equal width -->
<form class="ui form" action="{{.Link}}" method="post">
<form id="form_id" class="ui form" action="{{.Link}}" method="post">
{{.CsrfTokenHtml}}
<input type="hidden" name="action" value="update">
<input type="hidden" id="ai_engine_name" name="engine_names" value="">
@@ -111,11 +111,14 @@
Ascend NPU</a>
</div>
{{template "custom/wait_count_train" Dict "ctx" $}}
<div style="display: flex;align-items: center;margin-left: 155px;margin-top: 0.5rem;">
<i class="ri-error-warning-line" style="color: #f2711c;margin-right: 0.5rem;"></i>
<span style="color: #888;font-size: 12px;">{{.i18n.Tr "cloudbrain.train_dataset_path_rule" | Safe}}</span>
</div>
</div>
<div class="required inline min_title field">
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.job_name"}}</label>
<input style="width: 60%;" name="display_job_name" id="display_job_name" placeholder={{.i18n.Tr "repo.modelarts.train_job.job_name"}} value="{{.display_job_name}}" tabindex="3" onkeyup="this.value=this.value.replace(/[, ]/g,'')" autofocus required maxlength="36">
<span class="tooltips" style="margin-left:11.5rem;display: block;">{{.i18n.Tr "repo.cloudbrain_jobname_err"}}</span>
</div>

<div class="inline min_title field">
@@ -204,7 +207,7 @@
<div id="select-multi-dataset">

</div>
<span class="tooltips" style="margin-left: 11.5rem;margin-bottom: 1rem;">{{.i18n.Tr "cloudbrain.dataset_path_rule"}}</span>
<span class="tooltips" style="margin-left: 11.5rem;margin-bottom: 1rem;"></span>
<div class="inline min_title field">
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.run_parameter"}}</label>
<span id="add_run_para" style="margin-left: 0.5rem;cursor:pointer;color: rgba(3, 102, 214, 100);font-size: 14px;line-height: 26px;font-family: SourceHanSansSC-medium;"><i class="plus square outline icon"></i>{{.i18n.Tr "repo.modelarts.train_job.add_run_parameter"}}</span>
@@ -309,6 +312,12 @@
{{template "base/footer" .}}

<script>
let form = document.getElementById('form_id');
let createFlag = false
form.onsubmit = function (e) {
if(createFlag) return false
createFlag = true
}
let url_href = window.location.pathname.split('create')[0]
$(".ui.button").attr('href', url_href)
$('select.dropdown')
@@ -321,28 +330,16 @@
case 13:return false;
}
});
// let sever_num = $("#trainjob_work_server_num_select .text").text() //$('#trainjob_work_server_num')
// console.log("sever_num:",sever_num)
// $('.add').click(function(){
// sever_num.val(parseInt(sever_num.val())+1)
// if(sever_num.val()>=26){
// sever_num.val(parseInt(sever_num.val())-1)
// }
// })
// $('.min').click(function(){
// sever_num.val(parseInt(sever_num.val())-1)
// if(sever_num.val()<=0){
// sever_num.val(parseInt(sever_num.val())+1)
// }
// })
// 参数增加、删除、修改、保存
function Add_parameter(i) {
let placeholder_value='{{.i18n.Tr "repo.modelarts.train_job.parameter_value"}}'
let placeholder_name='{{.i18n.Tr "repo.modelarts.train_job.parameter_name"}}'
value = '<div class="two fields width85" id= "para' + i + '">' +
'<div class="field">' +
'<input type="text" name="shipping_first-name" required placeholder={{.i18n.Tr "repo.modelarts.train_job.parameter_name"}}> ' +
'<input type="text" name="shipping_first-name" required placeholder="' + placeholder_name+ '">' +
'</div> ' +
'<div class="field"> ' +
'<input type="text" name="shipping_last-name" required placeholder={{.i18n.Tr "repo.modelarts.train_job.parameter_value"}}>' +
'<input type="text" name="shipping_last-name" required placeholder="' + placeholder_value+ '">' +
'</div>' +
'<span>' +
'<i class="trash icon">' +


+ 79
- 80
templates/repo/modelarts/trainjob/show.tmpl View File

@@ -274,10 +274,14 @@


{{if .CanDel}}
<a class="ti-action-menu-item" onclick="deleteVersion({{.VersionName}})"
<a class='ti-action-menu-item delete-show-version {{if eq .Status "CREATING" "STOPPING" "WAITING" "STARTING" "RUNNING" "KILLING" "INIT"}}disabled {{end}}'
id="{{.VersionName}}-delete"
data-jobid="{{.JobID}}"
data-repopath="{{$.RepoRelPath}}/modelarts/train-job"
data-version = "{{.VersionName}}"
style="color: #FF4D4F;">{{$.i18n.Tr "repo.delete"}}</a>
{{else}}
<a class="ti-action-menu-item disabled" onclick="deleteVersion({{.VersionName}})"
<a class="ti-action-menu-item disabled"
style="color: #FF4D4F;">{{$.i18n.Tr "repo.delete"}}</a>
{{end}}
</div>
@@ -299,7 +303,7 @@
class="cti-mgRight-sm">{{$.i18n.Tr "repo.modelarts.train_job.dura_time"}}:</span>
<span class="cti-mgRight-sm uc-accordionTitle-black"
id="{{.VersionName}}-duration-span">{{.TrainJobDuration}}</span>
<span id="refresh-status" data-tooltip="刷新" style="cursor: pointer;" data-inverted="" data-version="{{.VersionName}}">
<span class="refresh-status" data-tooltip="刷新" style="cursor: pointer;" data-inverted="" data-version="{{.VersionName}}">
<i class="redo icon redo-color"></i>
</span>
</div>
@@ -316,7 +320,7 @@
data-tab="first{{$k}}">{{$.i18n.Tr "repo.modelarts.train_job.config"}}</a>
<a class="item log_bottom" data-tab="second{{$k}}"
data-version="{{.VersionName}}">{{$.i18n.Tr "repo.modelarts.log"}}</a>
<a class="item metric_chart" data-tab="four{{$k}}" data-version="{{.VersionName}}">资源占用情况</a>
<a class="item metric_chart" data-tab="four{{$k}}" data-version="{{.VersionName}}">{{$.i18n.Tr "cloudbrain.resource_use"}}</a>
<a class="item load-model-file" data-tab="third{{$k}}" data-download-flag="{{$.canDownload}}" data-path="{{$.RepoLink}}/modelarts/train-job/{{.JobID}}/model_list" data-version="{{.VersionName}}" data-parents="" data-filename="" data-init="init" >{{$.i18n.Tr "repo.model_download"}}</a>
</div>
<div class="ui tab active" data-tab="first{{$k}}">
@@ -397,16 +401,7 @@
</div>
</td>
</tr>
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "repo.modelarts.train_job.compute_node"}}
</td>
<td class="ti-text-form-content">
<div class="text-span text-span-w">
{{.WorkServerNumber}}
</div>
</td>
</tr>
</tbody>
</table>
</div>
@@ -445,23 +440,7 @@
</div>
</td>
</tr>
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "repo.modelarts.train_job.train_dataset"}}
</td>

<td class="ti-text-form-content">
<div class="text-span text-span-w">
{{range $m ,$n := $.datasetList}}
{{if eq $k $m}}
{{range $f ,$g := $n}}
<a href="{{.RepositoryLink}}" target="_blank">{{.DatasetName}}</a>
{{end}}
{{end}}
{{end}}
</div>
</td>
</tr>
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "repo.modelarts.train_job.run_parameter"}}
@@ -486,10 +465,38 @@
</div>
</td>
</tr>
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "repo.modelarts.train_job.compute_node"}}
</td>
<td class="ti-text-form-content">
<div class="text-span text-span-w">
{{.WorkServerNumber}}
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div style="clear:both">
<table style="border:none" class="ui fixed small stackable table">
<thead>
<tr><th style="color: #8a8e99;font-size:12px" class="three wide left aligned">{{$.i18n.Tr "dataset.file"}}</th>
</tr></thead>
<tbody>
{{range $m ,$n := $.datasetList}}
{{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>
</tr>
{{end}}
{{end}}
{{end}}
</tbody>
</table>
</div>
</div>

</div>
@@ -507,11 +514,11 @@
<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;"
<a title="{{$.i18n.Tr "repo.log_scroll_start"}}" 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">
<a title="滚动到底部" style="position: absolute; bottom: 10px;right: -32px;cursor: pointer;"
<span class="log-info-{{.VersionName}}">
<a title="{{$.i18n.Tr "repo.log_scroll_end"}}" style="position: absolute; bottom: 10px;right: -32px;cursor: pointer;"
class="log_bottom" data-version="{{.VersionName}}"><i
class="icon-to-bottom"></i></a>
</span>
@@ -586,7 +593,7 @@
<div id="newmodel">
<div class="ui modal second">
<div class="header" style="padding: 1rem;background-color: rgba(240, 240, 240, 100);">
<h4 id="model_header">导入新模型</h4>
<h4 id="model_header">{{.i18n.Tr "repo.model.manage.import_new_model"}}</h4>
</div>
<div class="content content-padding">
<form id="formId" method="POST" class="ui form">
@@ -597,34 +604,34 @@

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

</div>
<div class="required six widde field">
<label>版本</label>
<label>{{.i18n.Tr "repo.model.manage.version"}}</label>
<input class="width70" id="VersionName" name="VersionName" readonly required>
</div>
</div>

<div class="required inline field" id="modelname">
<label>模型名称</label>
<label>{{.i18n.Tr "repo.model.manage.model_name"}}</label>
<input style="width: 45%;" id="name" name="Name" required maxlength="25"
onkeyup="this.value=this.value.replace(/[, ]/g,'')">
</div>
<div class="required inline field" id="verionname">
<label>模型版本</label>
<label>{{.i18n.Tr "repo.modelconvert.modelversion"}}</label>
<input style="width: 45%;" id="version" name="Version" value="" readonly required maxlength="255">
</div>
<div class="unite min_title inline field required">
<label>模型框架</label>
<label>{{.i18n.Tr "repo.model.manage.engine"}}</label>
<input type="hidden" id="Engine" name="Engine" required>
<input style="width: 45%;" id="Engine_name" name="Engine_name" readonly required maxlength="255">
</div>
<div class="unite min_title inline fields required">
<div class="field required">
<label for="modelSelectedFile">模型文件</label>
<label for="modelSelectedFile">{{.i18n.Tr "repo.model.manage.modelfile"}}</label>
</div>
<div class="thirteen wide field" style="position:relative">
<input id="modelSelectedFile" type="text" readonly required onclick="showMenu();" name="modelSelectedFile" >
@@ -634,12 +641,12 @@
</div>
</div>
<div class="inline field">
<label>模型标签</label>
<label>{{.i18n.Tr "repo.model.manage.modellabel"}}</label>
<input style="width: 83%;margin-left: 7px;" id="label" name="Label" maxlength="255"
placeholder='{{.i18n.Tr "repo.modelarts.train_job.label_place"}}'>
</div>
<div class="inline field">
<label for="description">模型描述</label>
<label for="description">{{.i18n.Tr "repo.model.manage.modeldesc"}}</label>
<textarea style="width: 83%;margin-left: 7px;" id="Description" name="Description" rows="3"
maxlength="255" placeholder='{{.i18n.Tr "repo.modelarts.train_job.new_place"}}'
onchange="this.value=this.value.substring(0, 255)"
@@ -729,7 +736,7 @@
hideMenu();
}
}
let dirKey="isOnlyDir--:&";
function loadSelectedModelFile(trainJob){
console.log("trainJob=" + trainJob);
$('#choice_file').dropdown('clear')
@@ -744,7 +751,7 @@
var zNodes=[];
var nodesMap={};
for (let i=0;i<n_length;i++){
parentNodeMap = nodesMap;
var parentNodeMap = nodesMap;
var fileSplits = data[i].FileName.split("/");
for(let j=0;j < fileSplits.length;j++){
if(fileSplits[j] == ""){
@@ -753,7 +760,22 @@
if(parentNodeMap[fileSplits[j]] == null){
parentNodeMap[fileSplits[j]] = {};
}
parentNodeMap = parentNodeMap[fileSplits[j]]
parentNodeMap = parentNodeMap[fileSplits[j]];
}
}
for (let i=0;i<n_length;i++){
var parentNodeMap = nodesMap;
var fileSplits = data[i].FileName.split("/");
for(let j=0;j < fileSplits.length;j++){
if(fileSplits[j] == ""){
if(data[i].FileName[data[i].FileName.length -1] =="/"){
if(Object.keys(parentNodeMap).length ==0){
parentNodeMap[dirKey]="true";
}
}
break;
}
parentNodeMap = parentNodeMap[fileSplits[j]];
}
}
convertToNode(zNodes,nodesMap);
@@ -773,12 +795,17 @@
node["name"] = keyList[i];
nodeList.push(node);
if(nodesMap[keyList[i]] != null && Object.keys(nodesMap[keyList[i]]).length >0){
node["children"]=[];
if(isFirst){
node["open"] = true;
isFirst= false;
if(nodesMap[keyList[i]][dirKey] != null){
node["open"] = false;
node["isParent"] = true;
}else{
node["children"]=[];
if(isFirst){
node["open"] = true;
isFirst= false;
}
convertToNode(node["children"],nodesMap[keyList[i]]);
}
convertToNode(node["children"],nodesMap[keyList[i]]);
}
}
}
@@ -876,35 +903,7 @@
$('#name').val(modelName)
$('#version').val("0.0.1")
}
function deleteVersion(version_name) {
stopBubbling(arguments.callee.caller.arguments[0])
let flag = 1;
$('.ui.basic.modal').modal({
onDeny: function () {
flag = false
},
onApprove: function () {
$.post(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/del_version`, { version_name: version_name }, (data) => {
if (data.VersionListCount === 0) {
location.href = `/${userName}/${repoPath}/modelarts/train-job`
} else {
$('#accordion' + version_name).remove()
}

}).fail(function (err) {
console.log(err);
});
flag = true
},
onHidden: function () {
if (flag == false) {
$('.alert').html('您已取消操作').removeClass('alert-success').addClass('alert-danger').show().delay(1500).fadeOut();
}
}
})
.modal('show')

}




+ 13
- 17
templates/repo/modelarts/trainjob/version_new.tmpl View File

@@ -55,6 +55,7 @@
<div class="repository">
{{template "repo/header" .}}
<div class="ui container">
<div class="cloudbrain-type" style="display: none;" data-cloudbrain-type="{{.datasetType}}" data-repo-link="{{.RepoLink}}" data-dataset-uuid="{{.uuid}}" data-dataset-name="{{.dataset_name}}"></div>
{{template "base/alert" .}}
<h4 class="ui top attached header">
{{.i18n.Tr "repo.modelarts.train_job.new"}}
@@ -72,6 +73,11 @@
<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}}">
{{template "custom/wait_count_train" Dict "ctx" $}}
<div style="display: flex;align-items: center;margin-left: 155px;margin-top: 0.5rem;">
<i class="ri-error-warning-line" style="color: #f2711c;margin-right: 0.5rem;"></i>
<span style="color: #888;font-size: 12px;">{{.i18n.Tr "cloudbrain.train_dataset_path_rule" | Safe}}</span>
</div>
<h4 class="unite title ui header ">{{.i18n.Tr "repo.modelarts.train_job.basic_info"}}:</h4>
<div class="required unite min_title inline field">
<label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.job_name"}}</label>
@@ -151,22 +157,10 @@
</span>
<a href="https://git.openi.org.cn/OpenIOSSG/MINIST_Example" target="_blank">{{.i18n.Tr "cloudbrain.view_sample"}}</a>
</div>
<div class="required unite min_title inline field">
<label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.dataset"}}</label>
<select class="ui dropdown width80" id="trainjob_datasets" name="attachment" placeholder="{{.i18n.Tr "cloudbrain.select_dataset"}}">
{{if .dataset_name}}
<option name="attachment" value="{{.uuid}}">{{.dataset_name}}</option>
{{end}}
{{range .attachments}}
<option value="">{{$.i18n.Tr "cloudbrain.select_dataset"}}</option>
{{if ne $.uuid .UUID}}
<option name="attachment" value="{{.UUID}}">{{.Attachment.Name}}</option>
{{end}}
{{end}}
</select>
<span class="tooltips">{{.i18n.Tr "cloudbrain.dataset_path_rule"}}</span>
</div>
<div id="select-multi-dataset">

</div>
<span class="tooltips" style="margin-left: 11.5rem;margin-bottom: 1rem;"></span>
<div class="inline unite min_title field">
<label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.run_parameter"}}</label>
<span id="add_run_para" style="margin-left: 0.5rem;cursor:pointer;color: rgba(3, 102, 214, 100);font-size: 14px;line-height: 26px;font-family: SourceHanSansSC-medium;"><i class="plus square outline icon"></i>{{.i18n.Tr "repo.modelarts.train_job.add_run_parameter"}}</span>
@@ -286,12 +280,14 @@

// 参数增加、删除、修改、保存
function Add_parameter(i){
let placeholder_value='{{.i18n.Tr "repo.modelarts.train_job.parameter_value"}}'
let placeholder_name='{{.i18n.Tr "repo.modelarts.train_job.parameter_name"}}'
value = '<div class="two fields width85" id= "para'+ i +'">' +
'<div class="field">' +
'<input type="text" name="shipping_first-name" required placeholder={{.i18n.Tr "repo.modelarts.train_job.parameter_name"}}> ' +
'<input type="text" name="shipping_first-name" required placeholder="' + placeholder_name+ '">' +
'</div> ' +
'<div class="field"> ' +
'<input type="text" name="shipping_last-name" required placeholder={{.i18n.Tr "repo.modelarts.train_job.parameter_value"}}>' +
'<input type="text" name="shipping_last-name" required placeholder="' + placeholder_value+ '">' +
'</div>'+
'<span>' +
'<i class="trash icon">' +


+ 28
- 29
templates/repo/modelmanage/convertIndex.tmpl View File

@@ -47,13 +47,12 @@
{{if eq .MODEL_CONVERT_COUNT 0}}
<div class="ui placeholder segment bgtask-none">
<div class="ui icon header bgtask-header-pic"></div>
<div class="bgtask-content-header">未创建过模型转换任务</div>
<div class="bgtask-content-header">{{$.i18n.Tr "repo.modelconvert.notcreate"}}</div>
<div class="bgtask-content">
{{if eq .MODEL_COUNT 0}}
<div class="bgtask-content-txt">请您先导入<a href="{{.RepoLink}}/modelmanage/show_model">模型</a>,然后再对其进行转换。</div>
<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>
{{end}}
<div class="bgtask-content-txt">使用说明:可以参考启智AI协作平台<a
href="https://git.openi.org.cn/zeizei/OpenI_Learning">小白训练营课程。</a></div>
<div class="bgtask-content-txt">{{$.i18n.Tr "repo.platform_instructions"}}</div>

</div>
</div>
@@ -68,19 +67,19 @@
<div class="ui grid stackable" style="background: #f0f0f0;;">
<div class="row">
<div class="three wide column padding0">
<span style="margin:0 6px">任务名称</span>
<span style="margin:0 6px">{{$.i18n.Tr "repo.modelconvert.taskname"}}</span>
</div>
<div class="two wide column text center padding0">
<span>状态</span>
<span>{{$.i18n.Tr "repo.modelconvert.taskstatus"}}</span>
</div>
<div class="two wide column text center padding0">
<span>原模型框架</span>
<span>{{$.i18n.Tr "repo.modelconvert.srcengine"}}</span>
</div>
<div class="two wide column text center padding0">
<span>转换后格式</span>
<span>{{$.i18n.Tr "repo.modelconvert.outputformat"}}</span>
</div>
<div class="two wide column text center padding0">
<span>创建时间</span>
<span>{{$.i18n.Tr "repo.modelconvert.createtime"}}</span>
</div>
<div class="one wide column text center padding0">
<span>{{$.i18n.Tr "repo.cloudbrain_creator"}}</span>
@@ -143,10 +142,10 @@

{{if .IsCanOper}}
<a id="ai-download-{{.ID}}" href="{{$.Repository.HTMLURL}}/modelmanage/download_model_convert/{{.ID}}?AllDownload=true&a=1" class='ui basic {{if eq .Status "SUCCEEDED" "COMPLETED"}}blue {{else}}disabled {{end}}button' style="border-radius: .28571429rem;">
下载
{{$.i18n.Tr "repo.modelconvert.download"}}
</a>
{{else}}
<a class="ui basic disabled button">下载</a>
<a class="ui basic disabled button">{{$.i18n.Tr "repo.modelconvert.download"}}</a>
{{end}}
</div>
</div>
@@ -211,7 +210,7 @@
<input type="hidden" name="_csrf" value="">
<div class="unite min_title required inline fields" id="task_name">
<div class="three wide field right aligned">
<label for="model_convert_name">任务名称</label>
<label for="model_convert_name">{{$.i18n.Tr "repo.modelconvert.taskname"}}</label>
</div>
<div class="twelve wide field">
<input id="model_convert_name" name="model_convert_name" required maxlength="25" onkeyup="this.value=this.value.replace(/[, ]/g,'')">
@@ -219,10 +218,10 @@
</div>
<div class="unite min_title inline fields required">
<div class="three wide field right aligned">
<label for="choice_model">模型名称</label>
<label for="choice_model">{{$.i18n.Tr "repo.modelconvert.modelname"}}</label>
</div>
<div class="ui dropdown selection search eight wide field loading" id="choice_model" name="choice_model">
<div class="default text">选择模型</div>
<div class="default text">{{$.i18n.Tr "repo.modelconvert.selectmodel"}}</div>
<i class="dropdown icon"></i>
<div class="menu" id="model-name">
</div>
@@ -230,12 +229,12 @@
</div>
<div class="unite min_title inline fields required">
<div class="three wide field right aligned">
<label for="choice_version">模型版本</label>
<label for="choice_version">{{$.i18n.Tr "repo.modelconvert.modelversion"}}</label>
</div>
<div class="ui dropdown selection search eight wide field" id="choice_version">
<input type="hidden" id="ModelVersion" name="ModelVersion" required>
<div class="default text">选择版本</div>
<div class="default text">{{$.i18n.Tr "repo.modelconvert.selectversion"}}</div>
<i class="dropdown icon"></i>
<div class="menu" id="model-version">

@@ -244,11 +243,11 @@
</div>
<div class="unite min_title inline fields required">
<div class="three wide field right aligned">
<label for="choice_file">模型文件</label>
<label for="choice_file">{{$.i18n.Tr "repo.model.manage.modelfile"}}</label>
</div>
<div class="ui dropdown selection search eight wide field" id="choice_file">
<input type="hidden" id="ModelFile" name="ModelFile" required>
<div class="default text">选择模型文件</div>
<div class="default text">{{$.i18n.Tr "repo.modelconvert.selectmodelfile"}}</div>
<i class="dropdown icon"></i>
<div class="menu" id="model-file">

@@ -261,7 +260,7 @@
</div>
<div class="unite min_title inline fields required">
<div class="three wide field right aligned">
<label for="SrcEngine">原模型框架</label>
<label for="SrcEngine">{{$.i18n.Tr "repo.modelconvert.srcengine"}}</label>
</div>
<select id="SrcEngine" class="ui search dropdown eight wide field" placeholder="" style='color:#000000;' name="SrcEngine" onchange="javascript:srcEngineChanged()">
@@ -270,7 +269,7 @@
</div>
<div class="unite min_title required inline fields" id="inputdataformat_div">
<div class="three wide field right aligned">
<label for="inputdataformat">输入数据格式</label>
<label for="inputdataformat">{{$.i18n.Tr "repo.modelconvert.inputdataformat"}}</label>
</div>
<select id="inputdataformat" class="ui search dropdown eight wide field" placeholder="" style='width:50%' name="inputdataformat">
@@ -281,16 +280,16 @@
</div>
<div class="unite min_title required inline fields" id="inputshape_div">
<div class="three wide field right aligned">
<label for="inputshape">输入张量形状</label>
<label for="inputshape">{{$.i18n.Tr "repo.modelconvert.inputshape"}}</label>
</div>
<div class="eight wide field">
<input id="inputshape" name="inputshape" placeholder="如:1,1,32,32,与输入数据格式对应。" required maxlength="25">
<input id="inputshape" name="inputshape" placeholder="{{$.i18n.Tr "repo.modelconvert.inputshapetip"}}" required maxlength="25">
</div>
</div>
<div class="unite min_title inline fields required">
<div class="three wide field right aligned">
<label for="DestFormat">转换后格式</label>
<label for="DestFormat">{{$.i18n.Tr "repo.modelconvert.outputformat"}}</label>
</div>
<select id="DestFormat" class="ui search dropdown eight wide field" placeholder="" style='width:50%' name="DestFormat">
@@ -300,7 +299,7 @@
</div>
<div class="unite min_title inline fields">
<div class="three wide field right aligned">
<label for="NetOutputFormat">网络输出数据类型&nbsp;&nbsp;</label>
<label for="NetOutputFormat">{{$.i18n.Tr "repo.modelconvert.netoutputdata"}}&nbsp;&nbsp;</label>
</div>
<select id="NetOutputFormat" class="ui search dropdown eight wide field" placeholder="" style='width:50%' name="NetOutputFormat">
@@ -310,7 +309,7 @@
</div>
<div class="unite min_title inline fields">
<div class="three wide field right aligned">
<label for="Description">任务描述&nbsp;&nbsp;</label>
<label for="Description">{{$.i18n.Tr "repo.modelconvert.taskdesc"}}&nbsp;&nbsp;</label>
</div>
<div class="twelve wide field">
<textarea id="Description" name="Description" rows="1" maxlength="255" placeholder='{{.i18n.Tr "repo.modelarts.train_job.new_place"}}' onchange="this.value=this.value.substring(0, 255)" onkeydown="this.value=this.value.substring(0, 255)" onkeyup="this.value=this.value.substring(0, 256)"></textarea>
@@ -318,7 +317,7 @@
</div>
<div class="unite min_title inline field">
<button id="submitId" name="submitId" type="button" class="ui create_train_job green button" style="position: absolute;margin-left: 150px;">
新建任务
{{$.i18n.Tr "repo.modelconvert.newtask"}}
</button>
</div>
</div>
@@ -357,7 +356,7 @@
data['name']= $('#model_convert_name').val()

if(data['name']==""){
$('.ui.error.message').text("请输入任务名称。")
$('.ui.error.message').text("{{.i18n.Tr "repo.modelconvert.tasknameempty"}}")
$('.ui.error.message').css('display','block')
$("#task_name").addClass("error")
return false
@@ -371,7 +370,7 @@
data['inputshape']= $('#inputshape').val();

if(inputshapeNotValid(data['inputshape'])){
$('.ui.error.message').text("格式输入错误,请输入如:1,1,32,32,与输入数据格式对应。")
$('.ui.error.message').text("{{.i18n.Tr "repo.modelconvert.inputshapeerror"}}")
$('.ui.error.message').css('display','block')
$("#inputshape_div").addClass("error")
return false
@@ -411,7 +410,7 @@
.modal({
centered: false,
onShow:function(){
$('#model_header').text("创建模型转换任务")
$('#model_header').text("{{.i18n.Tr "repo.modelconvert.createtask"}}")
$('.ui.dimmer').css({"background-color":"rgb(136, 136, 136,0.7)"})
createModelName()
loadModelList()


+ 11
- 11
templates/repo/modelmanage/convertshowinfo.tmpl View File

@@ -173,7 +173,7 @@ td, th {
<h4 class="ui header" id="vertical-segment">
<div class="ui breadcrumb">
<a class="section" href="{{$.RepoLink}}/modelmanage/convert_model">
模型转换任务
{{.i18n.Tr "repo.modelconvert.taskurlname"}}
</a>
<div class="divider"> / </div>
<div class="active section">{{.Name}}</div>
@@ -243,7 +243,7 @@ td, th {

<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
输入张量形状
{{$.i18n.Tr "repo.modelconvert.inputshape"}}
</td>

<td class="ti-text-form-content">
@@ -255,7 +255,7 @@ td, th {
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
输入数据格式
{{$.i18n.Tr "repo.modelconvert.inputdataformat"}}
</td>

<td class="ti-text-form-content">
@@ -291,7 +291,7 @@ td, th {

<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
网络输出数据类型
{{$.i18n.Tr "repo.modelconvert.netoutputdata"}}
</td>
<td class="ti-text-form-content">
@@ -311,7 +311,7 @@ td, th {
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
模型名称
{{$.i18n.Tr "repo.modelconvert.modelname"}}
</td>

<td class="ti-text-form-content">
@@ -324,7 +324,7 @@ td, th {

<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
模型版本
{{$.i18n.Tr "repo.modelconvert.modelversion"}}
</td>

<td class="ti-text-form-content">
@@ -337,7 +337,7 @@ td, th {

<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
模型文件
{{$.i18n.Tr "repo.model.manage.modelfile"}}
</td>

<td class="ti-text-form-content">
@@ -350,7 +350,7 @@ td, th {

<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
原模型框架
{{$.i18n.Tr "repo.modelconvert.srcengine"}}
</td>

<td class="ti-text-form-content">
@@ -362,7 +362,7 @@ td, th {

<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
转换后格式
{{$.i18n.Tr "repo.modelconvert.outputformat"}}
</td>

<td class="ti-text-form-content">
@@ -439,10 +439,10 @@ td, th {
<div class="ui tab" data-tab="five">
<div style="position: relative;">
<span>
<a title="滚动到顶部" style="position: absolute; right: -32px;cursor: pointer;" class="log_top" data-version="V0001"><i class="icon-to-top"></i></a>
<a title="{{$.i18n.Tr "repo.log_scroll_start"}}" style="position: absolute; right: -32px;cursor: pointer;" class="log_top" data-version="V0001"><i class="icon-to-top"></i></a>
</span>
<span>
<a title="滚动到底部" style="position: absolute; bottom: 10px;right: -32px;cursor: pointer;" class="log_bottom" data-version="V0001"><i class="icon-to-bottom"></i></a>
<a title="{{$.i18n.Tr "repo.log_scroll_end"}}" style="position: absolute; bottom: 10px;right: -32px;cursor: pointer;" class="log_bottom" data-version="V0001"><i class="icon-to-bottom"></i></a>
</span>
<div id="log_npu_message" class="ui message message" style="display: none;">
<div id="log_npu_header"></div>


+ 47
- 26
templates/repo/modelmanage/index.tmpl View File

@@ -64,17 +64,16 @@
{{if eq $.MODEL_COUNT 0}}
<div class="ui placeholder segment bgtask-none">
<div class="ui icon header bgtask-header-pic"></div>
<div class="bgtask-content-header">未创建过模型</div>
<div class="bgtask-content-header">{{$.i18n.Tr "repo.model.manage.notcreatemodel"}}</div>
<div class="bgtask-content">
{{if $.RepoIsEmpty}}
<div class="bgtask-content-txt">代码版本:您还没有初始化代码仓库,请先<a href="{{.RepoLink}}">创建代码版本;</a></div>
<div class="bgtask-content-txt">{{$.i18n.Tr "repo.model.manage.init1"}}<a href="{{.RepoLink}}">{{$.i18n.Tr "repo.model.manage.init2"}}</a></div>
{{end}}
{{if eq $.TRAIN_COUNT 0}}
<div class="bgtask-content-txt">训练任务:您还没创建过训练任务,请先创建<a
href="{{.RepoLink}}/modelarts/train-job">训练任务</a>。</div>
<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>
{{end}}
<div class="bgtask-content-txt">使用说明:可以参考启智AI协作平台<a
href="https://git.openi.org.cn/zeizei/OpenI_Learning">小白训练营课程。</a></div>
<div class="bgtask-content-txt">{{$.i18n.Tr "repo.platform_instructions"}}</a></div>

</div>
<div style="display: none;">
@@ -108,11 +107,11 @@
<div id="deletemodel">
<div class="ui basic modal first">
<div class="ui icon header">
<i class="trash icon"></i> 删除模型
<i class="trash icon"></i> {{.i18n.Tr "repo.model.manage.delete"}}
</div>

<div class="content">
<p>你确认删除该模型么?此模型一旦删除不可恢复。</p>
<p>{{.i18n.Tr "repo.model.manage.delete_confirm"}}</p>
</div>
<div class="actions">
<div class="ui red basic inverted cancel button">
@@ -139,21 +138,21 @@
<input type="hidden" name="_csrf" value="">
<div class="inline fields">
<div class="required two wide field right aligned">
<label for="JobId">选择训练任务</label>
<label for="JobId">{{.i18n.Tr "repo.model.manage.select.trainjob"}}</label>
</div>
<div class="required thirteen wide inline field">
<div class="ui dropdown selection search loading" id="choice_model">
<input type="hidden" id="JobId" name="JobId" required>
<div class="default text">选择训练任务</div>
<div class="default text">{{.i18n.Tr "repo.model.manage.select.trainjob"}}</div>
<i class="dropdown icon"></i>
<div class="menu" id="job-name">
</div>
</div>
<label for="VersionName">版本</label>
<label for="VersionName">{{.i18n.Tr "repo.model.manage.version"}}</label>
<span>&nbsp;</span>
<div class="ui dropdown selection search" id="choice_version">
<input type="hidden" id="VersionName" name="VersionName" required>
<div class="default text">选择版本</div>
<div class="default text">{{.i18n.Tr "repo.model.manage.select.version"}}</div>
<i class="dropdown icon"></i>
<div class="menu" id="job-version">

@@ -163,7 +162,7 @@
</div>
<div class="required inline fields" id="modelname">
<div class="two wide field right aligned">
<label for="Name">模型名称</label>
<label for="Name">{{.i18n.Tr "repo.model.manage.model_name"}}</label>
</div>
<div class="eight wide field">
<input id="name" name="Name" required maxlength="25" onkeyup="this.value=this.value.replace(/[, ]/g,'')">
@@ -171,7 +170,7 @@
</div>
<div class="required inline fields" id="verionname">
<div class="two wide field right aligned">
<label for="Version">模型版本</label>
<label for="Version">{{.i18n.Tr "repo.model.manage.version"}}</label>
</div>
<div class="eight wide field">
<input id="version" name="Version" value="" readonly required maxlength="255">
@@ -180,11 +179,11 @@

<div class="unite min_title inline fields required">
<div class="two wide field right aligned">
<label for="Engine">模型框架</label>
<label for="Engine">{{.i18n.Tr "repo.model.manage.engine"}}</label>
</div>
<div class="ui ten wide field dropdown selection search" id="choice_Engine">
<input type="hidden" id="Engine" name="Engine" required>
<div class="default text newtext">选择模型框架</div>
<div class="default text newtext">{{.i18n.Tr "repo.model.manage.select.engine"}}</div>
<i class="dropdown icon"></i>
<div class="menu" id="job-Engine">

@@ -195,7 +194,7 @@

<div class="unite min_title inline fields required">
<div class="two wide field right aligned">
<label for="modelSelectedFile">模型文件</label>
<label for="modelSelectedFile">{{.i18n.Tr "repo.model.manage.modelfile"}}</label>
</div>
<div class="thirteen wide field" style="position:relative">
<input id="modelSelectedFile" type="text" readonly required onclick="showMenu();" name="modelSelectedFile" >
@@ -207,7 +206,7 @@

<div class="inline fields">
<div class="two wide field right aligned">
<label for="Label">模型标签 &nbsp</label>
<label for="Label">{{.i18n.Tr "repo.model.manage.modellabel"}} &nbsp</label>
</div>
<div class="thirteen wide field">
<input id="label" name="Label" maxlength="255" placeholder='{{.i18n.Tr "repo.modelarts.train_job.label_place"}}'>
@@ -215,7 +214,7 @@
</div>
<div class="inline fields">
<div class="two wide field right aligned">
<label for="description">模型描述 &nbsp</label>
<label for="description">{{.i18n.Tr "repo.model.manage.modeldesc"}} &nbsp</label>
</div>
<div class="thirteen wide field">
<textarea id="Description" name="Description" rows="3"
@@ -325,6 +324,7 @@
$('#name').val(modelName)
$('#version').val("0.0.1")
}
let dirKey="isOnlyDir--:&";
function showcreate(obj) {
$('.ui.modal.second')
.modal({
@@ -460,7 +460,7 @@
var zNodes=[];
var nodesMap={};
for (let i=0;i<n_length;i++){
parentNodeMap = nodesMap;
var parentNodeMap = nodesMap;
var fileSplits = data[i].FileName.split("/");
for(let j=0;j < fileSplits.length;j++){
if(fileSplits[j] == ""){
@@ -469,7 +469,22 @@
if(parentNodeMap[fileSplits[j]] == null){
parentNodeMap[fileSplits[j]] = {};
}
parentNodeMap = parentNodeMap[fileSplits[j]]
parentNodeMap = parentNodeMap[fileSplits[j]];
}
}
for (let i=0;i<n_length;i++){
var parentNodeMap = nodesMap;
var fileSplits = data[i].FileName.split("/");
for(let j=0;j < fileSplits.length;j++){
if(fileSplits[j] == ""){
if(data[i].FileName[data[i].FileName.length -1] =="/"){
if(Object.keys(parentNodeMap).length ==0){
parentNodeMap[dirKey]="true";
}
}
break;
}
parentNodeMap = parentNodeMap[fileSplits[j]];
}
}
convertToNode(zNodes,nodesMap);
@@ -488,12 +503,18 @@
node["name"] = keyList[i];
nodeList.push(node);
if(nodesMap[keyList[i]] != null && Object.keys(nodesMap[keyList[i]]).length >0){
node["children"]=[];
if(isFirst){
node["open"] = true;
isFirst= false;
if(nodesMap[keyList[i]][dirKey] != null){
node["open"] = false;
node["isParent"] = true;
}else{
node["children"]=[];
if(isFirst){
node["open"] = true;
isFirst= false;
}
convertToNode(node["children"],nodesMap[keyList[i]]);
}
convertToNode(node["children"],nodesMap[keyList[i]]);
}
}
}


+ 12
- 7
templates/repo/modelmanage/showinfo.tmpl View File

@@ -86,7 +86,7 @@
</div>
<div class="ui tab active" data-tab="first">
<div class="half-table">
<span class="model_header_text">基本信息</span>
<span class="model_header_text">{{$.i18n.Tr "repo.model.manage.baseinfo"}}</span>
<table class="tableStyle" style="margin-top:20px;">
<tbody>
<tr>
@@ -125,9 +125,9 @@
</td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">训练任务</td>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.model.manage.createtrainjob"}}</td>
<td class="ti-text-form-content word-elipsis">
<a id="DisplayJobNameHref" class="title" style="font-size: 14px;">
<a id="DisplayJobNameHref" class="title" style="font-size: 14px;" target="_blank">
<span id="DisplayJobName" class="fitted" style="width: 90%;vertical-align: middle;"></span>
</a>
</td>
@@ -472,10 +472,15 @@ function renderBrend(ID,version_name,parents,filename,init){
$('input[name=modelback]').val(filename)
}else{
$('input[name=model]').val(parents)
$('input[name=modelbac]').val(filename)
$('#file_breadcrumb a.section:contains(${filename})').nextAll().remove()
$('#file_breadcrumb a.section:contains(${filename})').replaceWith(`<div class='active section'>${filename}</div>`)
$('#file_breadcrumb div.section:contains(${filename})').append("<div class='divider'> / </div>")
$('input[name=modelback]').val(filename)
let selectEle = $('#file_breadcrumb a.section').filter(
(index, item) => {
return item.text == filename;
}
);
selectEle.nextAll().remove();
selectEle.after("<div class='divider'> / </div>");
selectEle.replaceWith(`<div class='active section'>${filename}</div>`);
}
}


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

@@ -6,6 +6,10 @@
data-debug-again="{{$.i18n.Tr "repo.debug_again"}}" data-debug-task="{{$.i18n.Tr "cloudbrain.DEBUG"}}"
data-train-task="{{$.i18n.Tr "cloudbrain.TRAIN"}}" data-inference-task="{{$.i18n.Tr "cloudbrain.INFERENCE"}}"
data-benchmark-task="{{$.i18n.Tr "cloudbrain.BENCHMARK"}}"
data-all-cluster="{{.i18n.Tr "cloudbrain.all_resource_cluster"}}"
data-all-aiCenter="{{.i18n.Tr "cloudbrain.all_ai_center"}}"
data-cluster-c2net="{{.i18n.Tr "cloudbrain.resource_cluster_c2net"}}"
data-cluster-openi="{{.i18n.Tr "cloudbrain.resource_cluster_openi"}}"
data-all-task="{{.i18n.Tr "admin.cloudbrain.all_task_types"}}"
data-all-compute="{{.i18n.Tr "admin.cloudbrain.all_computing_resources"}}"
data-all-status="{{.i18n.Tr "admin.cloudbrain.all_status"}}"></div>


+ 7
- 3
web_src/js/components/MinioUploader.vue View File

@@ -18,10 +18,12 @@
<label
class="el-form-item__label"
style="width: 140px; position: absolute; left: -140px"
>上传状态:</label
>{{ upload_status }}:</label
>
<div v-for="(item, index) in uploadFiles" class="datast-upload-progress">
<span class="dataset-name nowrap">{{ item.name }}</span>
<span class="dataset-name nowrap" :title="item.name">{{
item.name
}}</span>
<div class="dataset-progress">
<el-progress
:text-inside="true"
@@ -101,6 +103,7 @@ export default {
btnFlag: false,
cancel: "",
upload: "",
upload_status: "",
uploadFiles: [],
uploadFilesAddId: [],
// allUploadFiles: [],
@@ -117,6 +120,7 @@ export default {
this.repoPath = this.dropzoneParams.data("repopath");
this.cancel = this.dropzoneParams.data("cancel");
this.upload = this.dropzoneParams.data("upload");
this.upload_status = this.dropzoneParams.data("upload-status");
let previewTemplate = `
<div class="dz-preview dz-file-preview">
<div class="dz-image">
@@ -718,7 +722,7 @@ export default {
}
.datast-upload-progress .dataset-name {
text-align: right;
width: 120px;
width: 200px;
margin-right: 1rem;
}
.datast-upload-progress .dataset-progress {


+ 20
- 14
web_src/js/components/Model.vue View File

@@ -14,7 +14,7 @@
>
<el-table-column
prop="Name"
label="模型名称"
:label="i18n.model_name"
align="left"
min-width="18%"
>
@@ -28,7 +28,7 @@
</el-table-column>
<el-table-column
prop="Version"
label="版本"
:label="i18n.model_version"
align="center"
min-width="6.5%"
>
@@ -39,7 +39,7 @@
<el-table-column
prop="VersionCount"
label="版本数"
:label="i18n.model_version_num"
align="center"
min-width="7.5%"
>
@@ -50,7 +50,7 @@

<el-table-column
prop="Size"
label="模型大小"
:label="i18n.model_size"
align="center"
min-width="10.5%"
>
@@ -60,7 +60,7 @@
</el-table-column>
<el-table-column
prop="EngineName"
label="模型框架"
:label="i18n.model_egine"
align="center"
min-width="8.5%"
>
@@ -70,7 +70,7 @@
</el-table-column>
<el-table-column
prop="ComputeResource"
label="计算资源"
:label="i18n.model_compute_resource"
align="center"
min-width="10.5%"
>
@@ -80,7 +80,7 @@
</el-table-column>
<el-table-column
prop="CreatedUnix"
label="创建时间"
:label="i18n.model_create_time"
align="center"
min-width="13.75%"
>
@@ -90,7 +90,7 @@
</el-table-column>
<el-table-column
prop="UserName"
label="创建者"
:label="i18n.model_creator"
align="center"
min-width="6.75%"
>
@@ -101,12 +101,12 @@
</template>
</el-table-column>

<el-table-column label="操作" min-width="18%" align="center">
<el-table-column :label="i18n.model_operation" min-width="18%" align="center">
<template slot-scope="scope">
<div class="space-around">
<a :style="{visibility:!scope.row.Children ? 'visible':'hidden'}" :class="{'disabled':!scope.row.IsCanOper}" @click="showcreateVue(scope.row.Name,scope.row.Version,scope.row.Label)">创建新版本</a>
<a :href="loadhref+scope.row.ID" :class="{'disabled':!scope.row.IsCanOper}">下载</a>
<a :class="{'disabled':!scope.row.IsCanDelete}" @click="deleteModel(scope.row.ID,scope.row.cName,scope.row.rowKey)">删除</a>
<a :style="{visibility:!scope.row.Children ? 'visible':'hidden'}" :class="{'disabled':!scope.row.IsCanOper}" @click="showcreateVue(scope.row.Name,scope.row.Version,scope.row.Label)">{{i18n.model_create_new_ver}}</a>
<a :href="loadhref+scope.row.ID" :class="{'disabled':!scope.row.IsCanOper}">{{i18n.model_download}}</a>
<a :class="{'disabled':!scope.row.IsCanDelete}" @click="deleteModel(scope.row.ID,scope.row.cName,scope.row.rowKey)">{{i18n.model_delete}}</a>
</div>
</template>
@@ -141,7 +141,7 @@ export default {
},
data() {
return {
i18n: {},
currentPage:1,
pageSize:10,
totalNum:0,
@@ -451,7 +451,13 @@ export default {
this.url_create_newVersion = this.url + 'create_model'
this.url_create_newModel = this.url + 'create_new_model'
},

created() {
if (document.documentElement.attributes["lang"].nodeValue == "en-US") {
this.i18n = this.$locale.US;
} else {
this.i18n = this.$locale.CN;
}
},
beforeDestroy() { // 实例销毁之前对点击事件进行解绑
this.submitId.removeEventListener('click', this.submit);
}


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

@@ -0,0 +1,738 @@
<template>
<div>
<template v-if="showFlag">
<div v-loading="loadingLinkPage">
<div class="ui container">
<div class="ui mobile reversed stackable grid">
<div class="row" style="justify-content: space-between">
<div class="ui blue small menu compact selectcloudbrain">
<a class="item" :href="`${repoLink}/datasets`">{{
i18n.current_dataset
}}</a>
<a
class="active item"
:href="`${repoLink}/datasets/reference_datasets`"
>{{ i18n.linked_datasets }}</a
>
</div>
<button
style="margin-right: 2rem"
class="ui green button"
:class="{ disabled: !canWrite }"
@click="openDataset()"
>
{{ i18n.linked_datasets }}
</button>
</div>
<div class="row">
<div class="ui two cards" style="width: 100%">
<div
class="ui card refer-dataset-card"
v-for="(item, index) in datasetList"
:key="index"
@click="gotoDataset(item)"
>
<div class="content" style="border-bottom: none">
<div class="refer-dataset-card-content">
<div class="refer-dataset-card-title">
<span
:title="item.Title"
class="nowrap"
style="display: inline-block; max-width: 90%"
>{{ item.Title }}</span
><img
v-if="item.Recommend"
src="/img/jian.svg"
style="margin-left: 0.5rem"
/>
</div>
<template v-if="item.IsStaring">
<div style="display: flex">
<button
class="ui mini basic button dataset-card-flavor"
@click.stop="postStar(item, isSigned)"
>
<i class="ri-heart-fill" style="color: #fa8c16"></i>
<span style="margin-left: 0.3rem">{{
i18n.unfavorite
}}</span>
</button>
<a class="ui mini basic button card-flavor-num">
{{ item.NumStars }}
</a>
</div>
</template>
<template v-else>
<div style="display: flex">
<button
class="ui mini basic button dataset-card-flavor"
@click.stop="postStar(item, isSigned)"
>
<i class="ri-heart-line"></i>
<span style="margin-left: 0.3rem">{{
i18n.favorite
}}</span>
</button>
<a class="ui mini basic button card-flavor-num">
{{ item.NumStars }}
</a>
</div>
</template>
</div>
<div style="font-size: 12px; margin-top: 5px">
<a
v-if="item.Category"
:href="'/explore/datasets?category=' + item.Category"
class="ui repo-topic label topic"
@click.stop
>{{ i18n[item.Category] || item.Category }}</a
>
<a
v-if="item.Task"
:href="'/explore/datasets?task=' + item.Task"
class="ui repo-topic label topic"
@click.stop
>{{ i18n[item.Task] || item.Task }}</a
>
<a
v-if="item.License"
:href="'/explore/datasets?license=' + item.License"
class="ui repo-topic label topic"
@click.stop
>{{ item.License }}</a
>
</div>
<div class="description card-flavor-desc">
<p>{{ item.Description }}</p>
</div>
</div>
<div
class="extra content"
style="border-top: none !important"
>
<div style="display: flex; align-items: center">
<a
:href="'/' + item.Repo.OwnerName"
:title="item.Repo.OwnerName"
@click.stop
>
<img
class="ui avatar image"
style="width: 22px; height: 22px"
:src="'/user/avatar/' + item.Repo.OwnerName + '/-1'"
/>
</a>
<span
style="
color: #999999;
font-size: 12px;
margin-left: 0.5rem;
"
>{{ item.CreatedUnix | transformTimestamp }}</span
>
<span
style="
display: flex;
align-items: center;
justify-content: center;
margin: 0 1rem;
"
:title="i18n.citations"
>
<i class="ri-link"></i>
<span
style="
color: #101010;
font-size: 12px;
margin-left: 0.2rem;
"
>{{ item.UseCount }}</span
>
</span>
<span
style="display: flex; align-items: center; flex: 1"
:title="i18n.downloads"
>
<i class="ri-download-line"></i>
<span
style="
color: #101010;
font-size: 12px;
margin-left: 0.2rem;
"
>{{ item.DownloadTimes }}</span
>
</span>
<button
class="ui mini button"
:class="{ disabled1: !canWrite }"
@click.stop="
cancelReferData(item.ID, item.Title, canWrite)
"
>
{{ i18n.disassociate }}
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<template v-else>
<div class="ui container">
<div class="ui mobile reversed stackable grid">
<div class="row" style="justify-content: space-between">
<div class="ui blue small menu compact selectcloudbrain">
<a class="item" :href="`${repoLink}/datasets`">{{
i18n.current_dataset
}}</a>
<a
class="active item"
:href="`${repoLink}/datasets/reference_datasets`"
>{{ i18n.linked_datasets }}</a
>
</div>
<button class="ui green button" @click="openDataset()">
{{ i18n.linked_datasets }}
</button>
</div>
</div>
<div class="ui placeholder segment bgtask-none">
<div class="ui icon header bgtask-header-pic"></div>
<div class="bgtask-content-header">{{ i18n.not_link_dataset }}</div>
<div class="bgtask-content">
<div class="bgtask-content-txt">
{{ i18n.no_link_dataset_tips1 }}
</div>
<div class="bgtask-content-txt">
{{ i18n.dataset_instructions_for_use
}}<a href="https://git.openi.org.cn/zeizei/OpenI_Learning">{{
i18n.dataset_camp_course
}}</a>
</div>
</div>
</div>
</div>
</template>

<el-dialog
:title="i18n.linked_datasets"
:visible.sync="dialogVisible"
:width="dialogWidth"
@closed="refreshData"
>
<div class="ui icon input dataset-search-vue">
<i
class="search icon"
style="cursor: pointer; pointer-events: auto"
@click="searchName"
></i>
<input
type="text"
:placeholder="i18n.search_dataset"
v-model="search"
@keydown.enter.stop.prevent="searchName"
/>
</div>
<el-row>
<el-col
:span="17"
style="
padding-right: 1rem;
border-right: 1px solid #f5f5f6;
position: relative;
"
>
<el-tabs v-model="activeName">
<el-tab-pane :label="i18n.public_dataset" name="first">
<el-row v-loading="loadingPublicPage">
<el-checkbox-group
v-model="checkList"
style="font-size: 14px; line-height: 1"
>
<div
v-for="(item, index) in publicDatasetList"
:key="index"
class="select-data-wrap"
>
<div class="dataset-header-vue">
<el-checkbox
:label="item.ID"
@change="(checked) => changeCheckbox(checked, item)"
:title="item.Title"
class="select-data-title"
style="display: flex; align-items: end"
><span class="ref-data-title">
<span
style="overflow: hidden; text-overflow: ellipsis"
>
{{ item.Title }}
</span>
<img
v-if="item.Recommend"
src="/img/jian.svg"
style="margin-left: 0.5rem"
/> </span
></el-checkbox>
<a
class="select-data-title select-data-href"
:href="`/${item.Repo.OwnerName}/${item.Repo.Name}/datasets`"
:title="`${item.Repo.OwnerName}/${item.Repo.Alias}`"
style="font-size: 12px"
>{{ item.Repo.OwnerName }}/{{ item.Repo.Alias }}</a
>
</div>
<div class="data-multiple-wrap" :title="item.Description">
{{ item.Description }}
</div>
</div>
</el-checkbox-group>
</el-row>
<div
class="ui container"
style="margin-top: 25px; text-align: center"
>
<el-pagination
background
@current-change="currentChange"
:current-page="currentPage"
:page-size="5"
layout="total, prev, pager, next"
:total="totalNum"
>
</el-pagination>
</div>
</el-tab-pane>
</el-tabs>
</el-col>
<el-col
:span="7"
style="
display: flex;
flex-direction: column;
height: 100%;
right: 0;
position: absolute;
padding: 0 1.5rem;
"
>
<div
style="
font-size: 14px;
height: 40px;
text-align: left;
color: #0066ff;
line-height: 40px;
"
>
{{ i18n.selected_data_file }}
</div>
<div
style="
flex: 1;
margin-top: 1.5rem;
margin-bottom: 1rem;
overflow-y: auto;
"
>
<el-checkbox-group v-model="checkList">
<el-checkbox
v-for="(item, index) in selectDatasetArray"
:key="index"
:label="item.ID"
:title="item.Title"
@change="(checked) => changeCheckSelected(checked, item)"
style="display: flex; margin: 0.5rem 0"
><span class="select-data-right">{{
item.Title
}}</span></el-checkbox
>
</el-checkbox-group>
</div>
<div style="text-align: end">
<el-button
@click.native="confirmDataset"
size="small"
style="
background: #389e0d;
color: #fff;
border: 1px solid #389e0d;
"
>{{ i18n.sure }}</el-button
>
</div>
</el-col>
</el-row>
</el-dialog>
</div>
</template>

<script>
const { _AppSubUrl, _StaticUrlPrefix, csrf } = window.config;

export default {
components: {},
data() {
return {
dialogWidth: "65%",
dialogVisible: false,
activeName: "first",
repoLink: "",
datasetList: [],
test: false,
checkList: [],
publicDatasetList: [],
showFlag: true,
search: "",
selectDatasetArray: [],
paramsPublics: { page: 1, q: "" },

i18n: {},

totalNum: 0,
currentPage: 1,
loadingLinkPage: false,
loadingPublicPage: false,
canWrite: true,
isSigned: false,
maxReferenceNum: 20,
isCurrentUrl: true,
};
},
methods: {
openDataset() {
this.checkList = this.datasetList.map((item) => {
this.selectDatasetArray.push({ ID: item.ID, Title: item.Title });
return item.ID;
});
this.dialogVisible = true;
this.getDatasetList();
},
refreshData() {
this.checkList = [];
this.selectDatasetArray = [];
},
gotoDataset(item) {
window.open(`/${item.Repo.OwnerName}/${item.Repo.Name}/datasets`);
},
currentChange(page) {
this.paramsPublics.page = page;
this.getDatasetList();
},
searchName() {
this.paramsPublics.q = this.search;
this.paramsPublics.page = 1;
this.getDatasetList();
},
cancelReferData(id, name, canWrite) {
if (!canWrite) {
return;
}
let url = `${this.repoLink}/datasets/reference_datasets/${id}`;
this.$axios
.delete(url)
.then((res) => {
if (res.data.Code === 0) {
this.$message.success(this.i18n.cancel_link_dataset.format(name));
let index = this.datasetList.findIndex((item) => {
return item.ID === id;
});
this.datasetList.splice(index, 1);
if (this.datasetList.length === 0) {
this.showFlag = false;
}
} else {
this.$message.error(res.data.Message);
}
})
.catch((err) => {
this.$message.error(this.i18n.dataset_link_failed);
console.log(err);
});
},
confirmDataset() {
this.submitReferDataset();
this.dialogVisible = false;
},
changeCheckbox(checked, item) {
if (this.checkList.length > this.maxReferenceNum) {
this.checkList.pop();
this.$message.error(
this.i18n.dataset_over_nums.format(this.maxReferenceNum)
);
return;
}
if (this.checkList.length === this.maxReferenceNum && !checked) {
this.$message.error(
this.i18n.dataset_over_nums.format(this.maxReferenceNum)
);
return;
}
if (checked) {
this.selectDatasetArray.push({ ID: item.ID, Title: item.Title });
} else {
let index = this.selectDatasetArray.findIndex((element) => {
return element.ID === item.ID;
});
this.selectDatasetArray.splice(index, 1);
}
},
changeCheckSelected(checked, item) {
let index = this.selectDatasetArray.findIndex((element) => {
return element.ID === item.ID;
});
this.selectDatasetArray.splice(index, 1);
},
postStar(item, isSigned) {
if (!isSigned) {
return;
}
if (item.IsStaring) {
let url = `${this.repoLink}/datasets/${item.ID}/unstar`;
this.$axios.put(url).then((res) => {
if (res.data.Code === 0) {
this.datasetList.forEach((element, i) => {
if (element.ID === item.ID) {
this.datasetList[i].NumStars -= 1;
this.datasetList[i].IsStaring = !this.datasetList[i].IsStaring;
}
});
}
});
} else {
let url = `${this.repoLink}/datasets/${item.ID}/star`;
this.$axios.put(url).then((res) => {
if (res.data.Code === 0) {
this.datasetList.forEach((element, i) => {
if (element.ID === item.ID) {
this.datasetList[i].NumStars += 1;
this.datasetList[i].IsStaring = !this.datasetList[i].IsStaring;
}
});
}
});
}
},

getSelectDatasetList() {
this.loadingLinkPage = true;
let url = `${this.repoLink}/datasets/reference_datasets_data`;
this.$axios.get(url).then((res) => {
this.loadingLinkPage = false;
if (!res.data) {
this.showFlag = false;
this.datasetList = [];
return;
} else {
this.datasetList = res.data;
this.datasetList.length
? (this.showFlag = true)
: (this.showFlag = false);
}
});
},
getDatasetList() {
this.loadingPublicPage = true;
let url = `${this.repoLink}/datasets/reference_datasets_available`;
this.$axios
.get(url, {
params: this.paramsPublics,
})
.then((res) => {
this.publicDatasetList = JSON.parse(res.data.data);
this.totalNum = parseInt(res.data.count);
this.loadingPublicPage = false;
});
},
submitReferDataset() {
if (this.checkList.length > this.maxReferenceNum) {
this.$message.error(
this.i18n.dataset_over_nums.format(this.maxReferenceNum)
);
return;
}
let url = `${this.repoLink}/datasets/reference_datasets`;
let data = this.qs.stringify(
{
_csrf: csrf,
dataset_id: this.checkList,
},
{ arrayFormat: "repeat" }
);
this.$axios
.post(url, data)
.then((res) => {
if (res.data.Code === 0) {
this.$message.success(this.i18n.dataset_link_success);
this.getSelectDatasetList();
} else {
this.$message.error(res.data.Message);
}
})
.catch((err) => {
this.$message.error(this.i18n.dataset_link_failed);
console.log(err);
});
},
},

filters: {
transformTimestamp(timestamp) {
const date = new Date(parseInt(timestamp) * 1000);
const Y = date.getFullYear() + "-";
const M =
(date.getMonth() + 1 < 10
? "0" + (date.getMonth() + 1)
: date.getMonth() + 1) + "-";
const D =
(date.getDate() < 10 ? "0" + date.getDate() : date.getDate()) + " ";

const dateString = Y + M + D;
return dateString;
},
},
watch: {
search(val) {
if (!val) {
this.searchName();
}
},
showFlag(val) {
if (!val || this.isCurrentUrl) {
document
.getElementById("header-dataset")
.setAttribute("href", this.repoLink + "/datasets");
} else {
document
.getElementById("header-dataset")
.setAttribute("href", this.repoLink + "/datasets/reference_datasets");
}
},
},
mounted() {
this.getSelectDatasetList();
},
created() {
this.repoLink = $(".reference-dataset").data("repolink") || "";
this.canWrite = $(".reference-dataset").data("canwrite");
this.isSigned = $(".reference-dataset").data("is-sign");
this.maxReferenceNum = $(".reference-dataset").data("max-reference-num");
this.isCurrentUrl = $(".reference-dataset").data("address");
if (document.documentElement.attributes["lang"].nodeValue == "en-US") {
this.i18n = this.$locale.US;
} else {
this.i18n = this.$locale.CN;
}
},
beforeDestroy() {},
};
</script>

<style scoped>
.dataset-search-vue {
z-index: 9999;
position: absolute;
right: 31%;
height: 30px;
top: 60px;
}
.refer-dataset-card {
cursor: pointer;
box-shadow: 0px 4px 4px 0px rgba(232, 232, 232, 0.6);
border: 1px solid rgba(232, 232, 232, 1);
}
.refer-dataset-card .refer-dataset-card-content {
font-size: 16px;
color: #0366d6;
font-family: SourceHanSansSC-medium;
height: 34px;
font-weight: bold;
display: flex;
align-items: center;
justify-content: space-between;
}
.refer-dataset-card-title {
display: flex;
align-items: center;
max-width: 80%;
width: 100%;
}
.dataset-card-flavor {
display: flex;
align-items: center;
padding: 0.3rem 0.5rem;
border: #888888;
border-top-right-radius: 0 !important;
border-bottom-right-radius: 0 !important;
margin-right: -1px;
}
.card-flavor-num {
padding: 0.5rem;
border: #888888;
border-top-left-radius: 0 !important;
border-bottom-left-radius: 0 !important;
cursor: default !important;
}
.card-flavor-desc {
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
display: -webkit-box;
overflow: hidden;
color: #999999;
font-size: 14px;
margin-top: 10px;
}
.select-data-wrap {
padding: 1rem 0;
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
}
.select-data-title {
flex: 1;
overflow: hidden;
}
.select-data-title .ref-data-title {
font-size: 18px;
color: #454545;
font-weight: 700;
display: flex;
align-items: baseline;
max-width: 100%;
}
.select-data-href {
text-align: right;
text-overflow: ellipsis;
max-width: 35%;
word-break: initial;
margin-left: 1rem;
white-space: nowrap;
}
/deep/ .el-checkbox-group .el-checkbox .el-checkbox__label {
display: flex;
max-width: 90%;
}
.select-data-right {
overflow: hidden;
vertical-align: middle;
text-overflow: ellipsis;
max-width: 100%;
display: inline-block;
}
.data-multiple-wrap {
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
display: -webkit-box;
max-width: 100%;
overflow: hidden;
padding-top: 1rem;
color: #888888;
font: 12px;
line-height: 20px;
margin-left: 2rem;
}
.disabled1 {
opacity: 0.45 !important;
}
</style>

+ 87
- 35
web_src/js/components/dataset/selectDataset.vue View File

@@ -11,9 +11,9 @@
v-if="benchmarkNew"
class="label-fix-width"
style="font-weight: normal"
>数据集</label
>{{i18n.dataset_label}}</label
>
<label v-else>数据集</label>
<label v-else>{{i18n.dataset_label}}</label>
<span
:class="
benchmarkNew === true ? 'dataset-train-span' : 'dataset-debug-span'
@@ -38,7 +38,7 @@
type="text"
class="disabled"
style="width: 48.5%"
placeholder="选择数据集文件"
:placeholder="i18n.dataset_select_placeholder"
required
/>
<input
@@ -46,7 +46,7 @@
type="text"
class="disabled"
:required="required"
placeholder="选择数据集文件"
:placeholder="i18n.dataset_select_placeholder"
/>
</span>

@@ -59,10 +59,10 @@
? 'select-dataset-button'
: 'select-dataset-button-color'
"
>选择数据集
>{{i18n.dataset_select}}
</el-button>
<el-dialog
title="选择数据集"
:title="i18n.dataset_select"
:visible.sync="dialogVisible"
:width="dialogWidth"
>
@@ -74,8 +74,8 @@
></i>
<input
type="text"
placeholder="搜数据集名称/描述..."
v-model="search"
:placeholder="i18n.dataset_search_placeholder"
v-model="search"
@keydown.enter.stop.prevent="searchName"
/>
</div>
@@ -90,7 +90,7 @@
>
<el-tabs v-model="activeName" @tab-click="handleClick">
<!-- 当前项目的数据集 -->
<el-tab-pane label="本项目" name="first" v-loading="loadingCurrent">
<el-tab-pane :label="i18n.dataset_current_repo" name="first" v-loading="loadingCurrent">
<el-row>
<el-tree
:data="currentDatasetList"
@@ -141,6 +141,15 @@
class="dataset-repolink dataset-nowrap"
@click.stop="return false;"
>
<i
class="ri-links-line"
style="color: #21ba45; margin-right: 0.3rem"
:title="i18n.dataset_relate"
v-if="
'/' + data.Repo.OwnerName + '/' + data.Repo.Name !==
repoLink
"
></i>
<a
:href="
'/' +
@@ -163,13 +172,13 @@
class="zip-loading"
v-if="data.DecompressState === 2"
>
正在解压缩
{{i18n.dataset_unziping}}
</span>
<span
class="unzip-failed"
v-if="data.DecompressState === 3"
>
解压失败
{{i18n.dataset_unzip_failed}}
</span>
</span>
</span>
@@ -192,7 +201,7 @@
</div>
</el-tab-pane>
<!-- 我上传的数据集 -->
<el-tab-pane label="我上传的" name="second" v-loading="loadingMy">
<el-tab-pane :label="i18n.dataset_my_upload" name="second" v-loading="loadingMy">
<el-row>
<el-tree
:data="myDatasetList"
@@ -265,13 +274,13 @@
class="zip-loading"
v-if="data.DecompressState === 2"
>
正在解压缩
{{i18n.dataset_unziping}}
</span>
<span
class="unzip-failed"
v-if="data.DecompressState === 3"
>
解压失败
{{i18n.dataset_unzip_failed}}
</span>
</span>
</span>
@@ -295,7 +304,7 @@
</el-tab-pane>
<!-- 公开的数据集 -->
<el-tab-pane
label="公开数据集"
:label="i18n.dataset_public"
name="third"
v-loading="loadingPublic"
>
@@ -371,13 +380,13 @@
class="zip-loading"
v-if="data.DecompressState === 2"
>
正在解压缩
{{i18n.dataset_unziping}}
</span>
<span
class="unzip-failed"
v-if="data.DecompressState === 3"
>
解压失败
{{i18n.dataset_unzip_failed}}
</span>
</span>
</span>
@@ -401,7 +410,7 @@
</el-tab-pane>
<!-- 我点赞的数据集 -->
<el-tab-pane
label="我收藏的"
:label="i18n.dataset_collected"
name="four"
v-loading="loadingFavorite"
>
@@ -477,13 +486,13 @@
class="zip-loading"
v-if="data.DecompressState === 2"
>
正在解压缩
{{i18n.dataset_unziping}}
</span>
<span
class="unzip-failed"
v-if="data.DecompressState === 3"
>
解压失败
{{i18n.dataset_unzip_failed}}
</span>
</span>
</span>
@@ -527,7 +536,7 @@
line-height: 40px;
"
>
已选数据文件
{{i18n.dataset_selected}}
</div>
<div style="flex: 1; margin-top: 1.5rem">
<el-checkbox-group v-model="checkList">
@@ -549,7 +558,7 @@
color: #fff;
border: 1px solid #389e0d;
"
>确定</el-button
>{{i18n.dataset_ok}}</el-button
>
</div>
</el-col>
@@ -576,7 +585,7 @@ export default {
activeName: "first",
search: "",
required: true,
i18n: {},
type: 0,
repoLink: "",
selectDatasetArray: [],
@@ -586,6 +595,8 @@ export default {
confirmFlag: false,

saveStatusList: [],
// 初始化已选择的数据集列表
hasSelectDatasetList: [],
//当前项目数据集页面配置的初始化
initCurrentPage: 1,
totalNumCurrent: 0,
@@ -644,6 +655,7 @@ export default {

//tree 勾选触发事件
onCheck(data, checkedInfo) {
this.hasSelectDatasetList = [];
if (
this.selectDatasetArray.length === 0 ||
this.selectDatasetArray.every((item) => item.id !== data.id)
@@ -654,10 +666,10 @@ export default {
})
) {
this.$refs[data.ref].setChecked(data.id, false, false);
this.$message.warning("不能选择相同名称的数据文件");
this.$message.warning(this.i18n.dataset_not_equal_file);
} else if (this.selectDatasetArray.length === 5) {
this.$refs[data.ref].setChecked(data.id, false, false);
this.$message.error("最多不超过五个文件");
this.$message.error(this.i18n.dataset_most);
} else {
this.selectDatasetArray.push(data);
}
@@ -671,9 +683,8 @@ export default {
return item.label;
});
this.saveStatusList = this.selectDatasetArray.map((item) => {
return item.UUID;
return item.id;
});
// this.confirmDatasetList = this.saveStatusList.join(";");
},
//已选择数据集checkbox group 勾选事件
changeCheckbox(checked, data) {
@@ -686,7 +697,6 @@ export default {
});
this.selectDatasetArray.splice(index, 1);
this.saveStatusList.splice(index, 1);
// this.confirmDatasetList = this.saveStatusList.join(";");
},
tableHeaderStyle({ row, column, rowIndex, columnIndex }) {
if (rowIndex === 0) {
@@ -722,17 +732,23 @@ export default {
.then((res) => {
this.loadingCurrent = false;
let data = JSON.parse(res.data.data);
console.log(data);
this.currentDatasetList = this.transformeTreeData(
data,
"currentTree",
this.paramsCurrent.page
);
this.initCurrentTreeNode = this.currentDatasetList[0]?.id ? [this.currentDatasetList[0].id] : [];
this.initCurrentTreeNode = this.currentDatasetList[0]?.id
? [this.currentDatasetList[0].id]
: [];
this.totalNumCurrent = parseInt(res.data.count);
let setCheckedKeysList = this.currentDatasetList.reduce(
(pre, cur) => {
cur.Attachments.forEach((item) => {
if (this.saveStatusList.includes(item.id)) {
if (
this.saveStatusList.includes(item.id) ||
this.hasSelectDatasetList.includes(item.id)
) {
pre.push(item.id);
}
});
@@ -763,7 +779,9 @@ export default {
"myTree",
this.paramsMy.page
);
this.initMyTreeNode = this.myDatasetList[0]?.id ? [this.myDatasetList[0].id] : [];
this.initMyTreeNode = this.myDatasetList[0]?.id
? [this.myDatasetList[0].id]
: [];
this.totalNumMy = parseInt(res.data.count);
let setCheckedKeysList = this.myDatasetList.reduce((pre, cur) => {
cur.Attachments.forEach((item) => {
@@ -796,7 +814,9 @@ export default {
"publicTree",
this.paramsPublics.page
);
this.initPublicTreeNode = this.publicDatasetList[0]?.id ? [this.publicDatasetList[0].id] : [];
this.initPublicTreeNode = this.publicDatasetList[0]?.id
? [this.publicDatasetList[0].id]
: [];
this.totalNumPublic = parseInt(res.data.count);
let setCheckedKeysList = this.publicDatasetList.reduce((pre, cur) => {
cur.Attachments.forEach((item) => {
@@ -830,7 +850,9 @@ export default {
"favoriteTree",
this.paramsFavorite.page
);
this.initFavoriteTreeNode = this.MyFavoriteDatasetList[0]?.id ? [this.MyFavoriteDatasetList[0].id] : [];
this.initFavoriteTreeNode = this.MyFavoriteDatasetList[0]?.id
? [this.MyFavoriteDatasetList[0].id]
: [];
this.totalNumFavorite = parseInt(res.data.count);
let setCheckedKeysList = this.MyFavoriteDatasetList.reduce(
(pre, cur) => {
@@ -949,13 +971,38 @@ export default {
mounted() {
this.type = $(".cloudbrain-type").data("cloudbrain-type");
this.repoLink = $(".cloudbrain-type").data("repo-link");
if ($(".cloudbrain-type").data("dataset-uuid")) {
this.hasSelectDatasetList = $(".cloudbrain-type")
.data("dataset-uuid")
.split(";");
let hasSelectDatasetName = $(".cloudbrain-type")
.data("dataset-name")
.split(";");
if (this.hasSelectDatasetList.length !== 0) {
this.saveStatusList = this.hasSelectDatasetList;
this.checkList = hasSelectDatasetName;
this.hasSelectDatasetList.forEach((item, index) => {
this.selectDatasetArray.push({
id: item,
label: hasSelectDatasetName[index],
});
});
}
this.confirmDataset();
}

if (
location.href.indexOf("benchmark") !== -1 ||
location.href.indexOf("train-job") !== -1
location.href.indexOf("train-job") !== -1 ||
location.href.indexOf("inference") !== -1
) {
console.log("this.benchmarkNew");
this.benchmarkNew = true;
}
if (location.href.indexOf("modelarts/notebook/create") !== -1 || location.href.indexOf("/cloudbrain/create") !== -1) {
if (
location.href.indexOf("modelarts/notebook/create") !== -1 ||
location.href.indexOf("/cloudbrain/create") !== -1
) {
this.required = false;
}
window.onresize = () => {
@@ -966,6 +1013,11 @@ export default {
},
created() {
this.setDialogWidth();
if (document.documentElement.attributes["lang"].nodeValue == "en-US") {
this.i18n = this.$locale.US;
} else {
this.i18n = this.$locale.CN;
}
},
};
</script>


+ 17
- 10
web_src/js/components/images/selectGrampusImages.vue View File

@@ -7,32 +7,32 @@
v-if="benchmarkNew"
class="label-fix-width"
style="font-weight: normal"
>镜像</label
>{{i18n.image_label}}</label
>
<label v-else>镜像</label>
<label v-else>{{i18n.image_label}}</label>
<input
v-if="benchmarkNew"
type="text"
name="image"
:value="imageAddress"
style="width: 48.5%"
placeholder="选择镜像或输入镜像地址"
:placeholder="i18n.image_select_placeholder"
/>
<input
v-else
type="text"
name="image"
:value="imageAddress"
placeholder="选择镜像或输入镜像地址"
:placeholder="i18n.image_select_placeholder"
/>
<el-button
type="text"
@click="dialogVisible = true"
icon="el-icon-plus"
style="color: #0366d6"
>选择镜像
>{{i18n.image_select}}
</el-button>
<el-dialog title="选择镜像" :visible.sync="dialogVisible" width="50%">
<el-dialog :title="i18n.image_select" :visible.sync="dialogVisible" width="50%">
<div
class="ui icon input"
style="z-index: 9999; position: absolute; right: 50px; height: 30px"
@@ -43,12 +43,12 @@
></i>
<input
type="text"
placeholder="搜镜像Tag/描述/标签..."
:placeholder="i18n.image_search_placeholder"
v-model="search"
/>
</div>
<el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane label="公开镜像" name="first" v-loading="loadingPublic">
<el-tab-pane :label="i18n.image_public" name="first" v-loading="loadingPublic">
<div
style="
display: flex;
@@ -120,7 +120,7 @@
selectImages(publicData.place, publicData.tag)
"
>
使用
{{i18n.image_use}}
</button>
</div>
</div>
@@ -169,6 +169,7 @@ export default {
},
tableDataPublic: [],
loadingPublic: false,
i18n: {},
};
},
methods: {
@@ -236,7 +237,13 @@ export default {
this.benchmarkNew = true;
}
},
created() {},
created() {
if (document.documentElement.attributes["lang"].nodeValue == "en-US") {
this.i18n = this.$locale.US;
} else {
this.i18n = this.$locale.CN;
}
},
};
</script>



+ 24
- 18
web_src/js/components/images/selectImages.vue View File

@@ -7,16 +7,16 @@
v-if="benchmarkNew"
class="label-fix-width"
style="font-weight: normal"
>镜像</label
>{{i18n.image_label}}</label
>
<label v-else>镜像</label>
<label v-else>{{i18n.image_label}}</label>
<input
v-if="benchmarkNew"
type="text"
name="image"
:value="imageAddress"
style="width: 48.5%"
placeholder="选择镜像或输入镜像地址"
:placeholder="i18n.image_select_placeholder"
required
/>
<input
@@ -24,7 +24,7 @@
type="text"
name="image"
:value="imageAddress"
placeholder="选择镜像或输入镜像地址"
:placeholder="i18n.image_select_placeholder"
required
/>
<el-button
@@ -32,9 +32,9 @@
@click="dialogVisible = true"
icon="el-icon-plus"
style="color: #0366d6"
>选择镜像
>{{i18n.image_select}}
</el-button>
<el-dialog title="选择镜像" :visible.sync="dialogVisible" width="50%">
<el-dialog :title="i18n.image_select" :visible.sync="dialogVisible" width="50%">
<div
class="ui icon input"
style="z-index: 9999; position: absolute; right: 50px; height: 30px"
@@ -45,12 +45,12 @@
></i>
<input
type="text"
placeholder="搜镜像Tag/描述/标签..."
:placeholder="i18n.image_search_placeholder"
v-model="search"
/>
</div>
<el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane label="公开镜像" name="first" v-loading="loadingPublic">
<el-tab-pane :label="i18n.image_public" name="first" v-loading="loadingPublic">
<div
style="
display: flex;
@@ -122,7 +122,7 @@
selectImages(publicData.place, publicData.tag)
"
>
使用
{{i18n.image_use}}
</button>
</div>
</div>
@@ -142,7 +142,7 @@
</div>
</el-tab-pane>

<el-tab-pane label="我的镜像" name="second" v-loading="loadingCustom">
<el-tab-pane :label="i18n.image_my" name="second" v-loading="loadingCustom">
<div
style="
display: flex;
@@ -208,7 +208,7 @@
selectImages(customData.place, customData.tag)
"
>
使用
{{i18n.image_use}}
</button>
<span
v-if="customData.status === 0"
@@ -217,7 +217,7 @@
<i class="CREATING"></i>
<span
style="margin-left: 0.4em; font-size: 12px; color: #5a5a5a"
>提交中</span
>{{i18n.image_commit}}</span
>
</span>
<span
@@ -228,11 +228,11 @@
<el-tooltip
class="item"
effect="dark"
content="检测提交镜像是否大小超过20G!"
:content="i18n.image_commit_content"
placement="left"
>
<span style="margin-left: 0.4em; font-size: 12px; color: red"
>提交失败</span
>{{i18n.image_commit_failed}}</span
>
</el-tooltip>
</span>
@@ -254,7 +254,7 @@
</div>
</el-tab-pane>

<el-tab-pane label="我收藏的镜像" name="third">
<el-tab-pane :label="i18n.image_collected" name="third">
<div
style="
display: flex;
@@ -324,7 +324,7 @@
class="ui primary basic button mini"
@click.stop.prevent="selectImages(starData.place, starData.tag)"
>
使用
{{i18n.image_use}}
</button>
</div>
</div>
@@ -368,7 +368,7 @@ export default {
paramsPublic: { page: 1, pageSize: 5, q: "", recommend: false },
tableDataPublic: [],
loadingPublic: false,
i18n: {},
currentPageCustom: 1,
pageSizeCustom: 5,
totalNumCustom: 0,
@@ -513,7 +513,13 @@ export default {
this.benchmark = true;
}
},
created() {},
created() {
if (document.documentElement.attributes["lang"].nodeValue == "en-US") {
this.i18n = this.$locale.US;
} else {
this.i18n = this.$locale.CN;
}
},
};
</script>



+ 48
- 4
web_src/js/features/cloudbrainShow.js View File

@@ -189,15 +189,59 @@ export default async function initCloudrainSow() {
console.log(err);
});
}
$("#refresh-status").click(function (e) {
$(".refresh-status").click(function (e) {
let version_name = $(this).data("version");
let ID = $(`#accordion${version_name}`).data("jobid");
let repoPath = $(`#accordion${version_name}`).data("repopath");
refreshStatusShow(version_name, ID, repoPath);
$(".log-info .log_bottom").trigger("click");
$(`.log-info-${version_name} .log_bottom`).trigger("click");
e.stopPropagation();
});
$(".stop-show-version").click(function (e) {
const ID = this.dataset.jobid;
const repoPath = this.dataset.repopath;
const version_name = this.dataset.version;
const url = `/api/v1/repos/${repoPath}/${ID}/stop_version`;
$.post(url, { version_name: version_name }, (data) => {
if (data.StatusOK === 0) {
$(`#${version_name}-stop`).removeClass("blue");
$(`#${version_name}-stop`).addClass("disabled");
refreshStatusShow(version_name, ID, repoPath);
}
}).fail(function (err) {
console.log(err);
});
e.stopPropagation();
});
$(".delete-show-version").click(function (e) {
const ID = this.dataset.jobid;
const repoPath = this.dataset.repopath;
const version_name = this.dataset.version;
const url = `/api/v1/repos/${repoPath}/${ID}/del_version`;
$(".ui.basic.modal")
.modal({
onApprove: function () {
$.post(url, { version_name: version_name }, (data) => {
console.log(data);
if (data.StatusOK === 0) {
if (data.VersionListCount === 0) {
location.href = `/${repoPath}`;
} else {
$("#accordion" + version_name).remove();
}
refreshStatusShow(version_name, ID, repoPath);
} else {
return;
}
}).fail(function (err) {
console.log(err);
});
},
})
.modal("show");

e.stopPropagation();
});
function refreshStatusShow(version_name, ID, repoPath) {
$.get(
`/api/v1/repos/${repoPath}/${ID}?version_name=${version_name}`,
@@ -322,8 +366,8 @@ export default async function initCloudrainSow() {
}
);
selectEle.nextAll().remove();
selectEle.after("<div class='divider'> / </div>");
selectEle.replaceWith(`<div class='active section'>${filename}</div>`);
selectEle.append("<div class='divider'> / </div>");
}
}

@@ -375,7 +419,7 @@ export default async function initCloudrainSow() {
html += "</a>";
html += "</span>";
html += "</td>";
html += "<td class='message seven wide'>";
html += "<td class='message1 seven wide'>";
if (data.Dirs[i].IsDir) {
html += "<span class='truncate has-emoji'></span>";
} else {


+ 45
- 20
web_src/js/features/cloudrbanin.js View File

@@ -182,6 +182,15 @@ export default async function initCloudrain() {
"CREATE_FAILED",
"STOPPED",
];
let deleteArray = [
"KILLED",
"FAILED",
"START_FAILED",
"COMPLETED",
"SUCCEEDED",
"CREATE_FAILED",
"STOPPED",
];
$.get(
`/api/v1/repos/${repoPath}/${jobID}?version_name=${versionname}`,
(data) => {
@@ -194,6 +203,10 @@ export default async function initCloudrain() {
if (stopArray.includes(data.JobStatus)) {
$("#" + versionname + "-stop").addClass("disabled");
}
if (deleteArray.includes(data.JobStatus)) {
$(`#${versionname}-delete`).removeClass("disabled");
$(`#${versionname}-delete`).addClass("blue");
}
if (data.JobStatus === "COMPLETED") {
$("#" + versionname + "-create-model")
.removeClass("disabled")
@@ -329,24 +342,6 @@ export default async function initCloudrain() {
console.log(err);
});
}

$(".stop-show-version").click(function (e) {
const ID = this.dataset.jobid;
const repoPath = this.dataset.repopath;
const version_name = this.dataset.version;
const url = `/api/v1/repos/${repoPath}/${ID}/stop_version`;
$.post(url, { version_name: version_name }, (data) => {
if (data.StatusOK === 0) {
$(`#${version_name}-stop`).removeClass("blue");
$(`#${version_name}-stop`).addClass("disabled");
refreshStatusShow(version_name, ID, repoPath);
}
}).fail(function (err) {
console.log(err);
});
e.stopPropagation();
});

function refreshStatus(version_name, ID, repoPath) {
const url = `/api/v1/repos/${repoPath}/${ID}/?version_name${version_name}`;
$.get(url, (data) => {
@@ -499,6 +494,18 @@ function userSearchControll() {
return;
}
const params = new URLSearchParams(window.location.search);
let cluster;
if ($(".cloudbrain_debug").length === 1) {
if (!params.get("cluster")) {
cluster = $(".cloudbrain_debug").data("all-cluster");
} else {
if (params.get("cluster") === "resource_cluster_c2net") {
cluster = $(".cloudbrain_debug").data("cluster-c2net");
} else {
cluster = $(".cloudbrain_debug").data("cluster-openi");
}
}
}
let jobType;
if ($(".cloudbrain_debug").length === 1) {
if (!params.get("jobType")) {
@@ -515,13 +522,16 @@ function userSearchControll() {
}
}
}
let aiCenter = !params.get("aiCenter")
? $(".cloudbrain_debug").data("all-aiCenter")
: params.get("aiCenter");
let listType = !params.get("listType")
? $(".cloudbrain_debug").data("all-compute")
: params.get("listType");
let jobStatus = !params.get("jobStatus")
? $(".cloudbrain_debug").data("all-status")
: params.get("jobStatus").toUpperCase();
const dropdownValueArray = [jobType, listType, jobStatus];
const dropdownValueArray = [cluster, aiCenter, jobType, listType, jobStatus];
$("#userCloud .default.text ").each(function (index, e) {
$(e).text(dropdownValueArray[index]);
});
@@ -532,6 +542,21 @@ function AdaminSearchControll() {
return;
}
const params = new URLSearchParams(window.location.search);
let cluster;
if ($(".cloudbrain_debug").length === 1) {
if (!params.get("cluster")) {
cluster = $(".cloudbrain_debug").data("all-cluster");
} else {
if (params.get("cluster") === "resource_cluster_c2net") {
cluster = $(".cloudbrain_debug").data("cluster-c2net");
} else {
cluster = $(".cloudbrain_debug").data("cluster-openi");
}
}
}
let aiCenter = !params.get("aiCenter")
? $(".cloudbrain_debug").data("all-aiCenter")
: params.get("aiCenter");
let jobType = !params.get("jobType")
? $(".cloudbrain_debug").data("all-task")
: params.get("jobType");
@@ -541,7 +566,7 @@ function AdaminSearchControll() {
let jobStatus = !params.get("jobStatus")
? $(".cloudbrain_debug").data("all-status")
: params.get("jobStatus").toUpperCase();
const dropdownValueArray = [jobType, listType, jobStatus];
const dropdownValueArray = [cluster, aiCenter, jobType, listType, jobStatus];
$("#adminCloud .default.text ").each(function (index, e) {
$(e).text(dropdownValueArray[index]);
});


+ 200
- 0
web_src/js/features/i18nVue.js View File

@@ -0,0 +1,200 @@
export const i18nVue = {
CN: {
computer_vision: "计算机视觉",
natural_language_processing: "自然语言处理",
speech_processing: "语音处理",
computer_vision_natural_language_processing: "计算机视觉、自然语言处理",
machine_translation: "机器翻译",
question_answering_system: "问答系统",
information_retrieval: "信息检索",
knowledge_graph: "知识图谱",
text_annotation: "文本标注",
text_categorization: "文本分类",
emotion_analysis: "情感分析",
language_modeling: "语言建模",
speech_recognition: "语音识别",
automatic_digest: "自动文摘",
information_extraction: "信息抽取",
description_generation: "说明生成",
image_classification: "图像分类",
face_recognition: "人脸识别",
image_search: "图像搜索",
target_detection: "目标检测",
image_description_generation: "图像描述生成",
vehicle_license_plate_recognition: "车辆车牌识别",
medical_image_analysis: "医学图像分析",
unmanned: "无人驾驶",
unmanned_security: "无人安防",
drone: "无人机",
vr_ar: "VR/AR",
"2_d_vision": "2-D视觉",
"2_5_d_vision": "2.5-D视觉",
"3_d_reconstruction": "3D重构",
image_processing: "图像处理",
video_processing: "视频处理",
visual_input_system: "视觉输入系统",
speech_coding: "语音编码",
speech_enhancement: "语音增强",
speech_recognition: "语音识别",
speech_synthesis: "语音合成",
current_dataset: "当前数据集",
linked_datasets: "关联数据集",
unfavorite: "取消收藏",
favorite: "收藏",
disassociate: "取消关联",
public_dataset: "公开数据集",
selected_data_file: "已选数据集",
sure: "确定",
search_dataset: "搜数据集名称/描述...",
citations: "引用次数",
downloads: "下载次数",
not_link_dataset: "还未关联过数据集",
no_link_dataset_tips1:
"您可以通过单击关联数据集按钮,将平台上公开数据集展示在这里。",
dataset_instructions_for_use: "使用说明:可以参考启智AI协作平台",
dataset_camp_course: "小白训练营课程",
dataset_link_success: "关联数据集成功!",
dataset_link_failed: "关联数据集失败!",
dataset_over_nums: "关联超过?个数据集",
cancel_link_dataset: "取消?关联数据集成功!",
image_label: "镜像",
image_select_placeholder: "选择镜像或输入镜像地址",
image_select: "选择镜像",
image_search_placeholder: "搜镜像Tag/描述/标签...",
image_public: "公开镜像",
image_use: "使用",
image_my: "我的镜像",
image_commit: "提交中",
image_commit_content: "检测提交镜像是否大小超过20G!",
image_commit_failed: "提交失败",
image_collected: "我收藏的镜像",
dataset_label: "数据集",
dataset_select_placeholder: "选择数据集文件",
dataset_select: "选择数据集",
dataset_search_placeholder: "搜数据集名称/描述...",
dataset_unziping: "正在解压缩",
dataset_unzip_failed: "解压失败",
dataset_my_upload: "我上传的",
dataset_current_repo: "本项目",
dataset_public: "公开数据集",
dataset_relate: "关联数据集",
dataset_collected: "我收藏的",
dataset_selected: "已选数据文件",
dataset_ok: "确定",
dataset_not_equal_file: "不能选择相同名称的数据文件",
dataset_most: "最多不超过五个文件",
model_name: "模型名称",
model_version: "版本",
model_version_num: "版本数",
model_size: "模型大小",
model_egine: "模型框架",
model_compute_resource: "计算资源",
model_create_time: "创建时间",
model_creator: "创建者",
model_operation: "操作",
model_create_new_ver: "创建新版本",
model_download: "下载",
model_delete: "删除",
},
US: {
computer_vision: "computer vision",
natural_language_processing: "natural language processing",
speech_processing: "speech processing",
computer_vision_natural_language_processing:
"computer vision and natural language processing",
machine_translation: "machine translation",
question_answering_system: "question answering system",
information_retrieval: "information retrieval",
knowledge_graph: "knowledge graph",
text_annotation: "text annotation",
text_categorization: "text categorization",
emotion_analysis: "emotion analysis",
language_modeling: "language modeling",
speech_recognition: "speech recognition",
automatic_digest: "automatic digest",
information_extraction: "information extraction",
description_generation: "description generation",
image_classification: "image classification",
face_recognition: "face recognition",
image_search: "image search",
target_detection: "target detection",
image_description_generation: "image description generation",
vehicle_license_plate_recognition: "vehicle license plate recognition",
medical_image_analysis: "medical image analysis",
unmanned: "unmanned",
unmanned_security: "unmanned security",
drone: "drone",
vr_ar: "VR/AR",
"2_d_vision": "2.D vision",
"2.5_d_vision": "2.5D vision",
"3_d_reconstruction": "3Dreconstruction",
image_processing: "image processing",
video_processing: "video processing",
visual_input_system: "visual input system",
speech_coding: "speech coding",
speech_enhancement: "speech enhancement",
speech_recognition: "speech recognition",
speech_synthesis: "speech synthesis",
current_dataset: "Current Dataset",
linked_datasets: "Linked Datasets",
unfavorite: "UnLike",
favorite: "Like",
disassociate: "Unlink",
public_dataset: "Public Dataset",
selected_data_file: "Selected DataSets",
sure: "Ok",
search_dataset: "Search dataset name/description ...",
citations: "Citations",
downloads: "Downloads",
not_link_dataset: "No datasets have been associated yet",
no_link_dataset_tips1:
"You can display public datasets on the platform here by clicking the New Linked Dataset button.",

dataset_instructions_for_use:
"Instructions for use: You can refer to Openi AI Collaboration Platform ",
dataset_camp_course: " Newcomer Training Camp Course",
dataset_link_success: "Linked dataset succeeded!",
dataset_link_failed: "Linked dataset Failed!",
dataset_over_nums: "Linked over ? datasets!",
cancel_link_dataset: "Cancel ? Linked dataset succeeded!",
image_label: "Image",
image_select_placeholder: "Select image or input image url",
image_select: "Select Image",
image_search_placeholder: "Search image tag/description/label...",
image_public: "Public Image",
image_use: "Use",
image_my: "My Images",
image_commit: "Commiting",
image_commit_content:
"Check whether the size of the submitted image exceeds 20g.",
image_commit_failed: "Commit failed",
image_collected: "My collected images",
dataset_label: "Dataset",
dataset_select_placeholder: "Select dataset file",
dataset_select: "Select dataset",
dataset_search_placeholder: "Search dataset name/description ...",
dataset_unziping: "Decompressing",
dataset_unzip_failed: "Decompression failed",
dataset_my_upload: "Upload by me",
dataset_current_repo: "Current Repository",
dataset_public: "Public dataset",
dataset_collected: "My collection",
dataset_relate: "Related dataset",
dataset_selected: "Selected dataset file",
dataset_ok: "OK",
dataset_not_equal_file: "Cannot select a data file with the same name.",
dataset_most: "Up to five files.",
model_name: "Model Name",
model_version: "Version",
model_version_num: "Total",
model_size: "Size",
model_egine: "Engine",
model_compute_resource: "Compute Resource",
model_create_time: "Created Time",
model_creator: "Creator",
model_operation: "Operation",
model_create_new_ver: "New Version",
model_download: "Download",
model_delete: "Delete",
},
};

+ 19
- 2
web_src/js/index.js View File

@@ -46,15 +46,19 @@ import initCloudrain from "./features/cloudrbanin.js";
import initCloudrainSow from "./features/cloudbrainShow.js";
import initImage from "./features/images.js";
import selectDataset from "./components/dataset/selectDataset.vue";
import referenceDataset from "./components/dataset/referenceDataset.vue";
// import $ from 'jquery.js'
import router from "./router/index.js";
import { Message } from "element-ui";

import { i18nVue } from "./features/i18nVue.js";

Vue.use(ElementUI);
Vue.prototype.$axios = axios;
Vue.prototype.$Cookies = Cookies;
Vue.prototype.qs = qs;
Vue.prototype.$message = Message;
Vue.prototype.$locale = i18nVue;
const { AppSubUrl, StaticUrlPrefix, csrf } = window.config;

Object.defineProperty(Vue.prototype, "$echarts", {
@@ -2900,6 +2904,7 @@ $(document).ready(async () => {
initVueDataAnalysis();
initVueWxAutorize();
initVueselectDataset();
initVuereferenceDataset();
initTeamSettings();
initCtrlEnterSubmit();
initNavbarContentToggle();
@@ -3520,7 +3525,7 @@ function initVueComponents() {
`${self.reposFilter}:${self.archivedFilter}:${self.privateFilter}`,
count
);
self.finalPage = Math.floor(count / self.searchLimit) + 1;
self.finalPage = Math.ceil(count / self.searchLimit);
self.updateHistory();
}
}).always(() => {
@@ -4532,6 +4537,16 @@ function initVueselectDataset() {
render: (h) => h(selectDataset),
});
}
function initVuereferenceDataset() {
const el = document.getElementById("reference-dataset");
if (!el) {
return;
}
new Vue({
el: el,
render: (h) => h(referenceDataset),
});
}
window.timeAddManual = function () {
$(".mini.modal")
.modal({
@@ -5086,7 +5101,7 @@ function initChartsNpu() {
axisLabel: {
interval: "auto",
},
name: "时间(min)",
name: "",
},
yAxis: {
show: true,
@@ -5142,7 +5157,9 @@ function initChartsNpu() {
};
return seriesOption;
});
let xAxisValue = res.Interval === 1 ? "时间(min)" : "时间(hour)";
let xLength = res.MetricsInfo[0].value.length;
options.xAxis.name = xAxisValue;
options.xAxis.data = Array.from(
{ length: xLength },
(_, index) => index


+ 1
- 1
web_src/less/_dashboard.less View File

@@ -100,7 +100,7 @@
}

.issue.title {
width: 80%;
width: 100%;
}

.push.news .content ul {


Loading…
Cancel
Save