#2648 V20220801合入develop

Merged
lewis merged 199 commits from V20220801 into develop 1 year ago
  1. +1
    -0
      .gitignore
  2. +4
    -1
      README.md
  3. +155
    -4
      models/cloudbrain.go
  4. +5
    -15
      models/cloudbrain_static.go
  5. +14
    -10
      models/dbsql/dataset_foreigntable_for_es.sql
  6. +1
    -1
      models/dbsql/repo_foreigntable_for_es.sql
  7. +8
    -7
      models/repo.go
  8. +3
    -0
      models/repo_activity_custom.go
  9. +15
    -1
      models/user_analysis_for_activity.go
  10. +43
    -5
      models/user_business_analysis.go
  11. +2
    -0
      modules/auth/cloudbrain.go
  12. +1
    -0
      modules/auth/grampus.go
  13. +46
    -0
      modules/auth/wechat/client.go
  14. +145
    -0
      modules/auth/wechat/template.go
  15. +24
    -20
      modules/cloudbrain/cloudbrain.go
  16. +2
    -1
      modules/context/context.go
  17. +1
    -1
      modules/git/repo_stats_custom.go
  18. +2
    -0
      modules/notification/base/notifier.go
  19. +4
    -0
      modules/notification/base/null.go
  20. +9
    -0
      modules/notification/notification.go
  21. +44
    -0
      modules/notification/wechat/wechat.go
  22. +7
    -1
      modules/setting/setting.go
  23. +5
    -2
      options/locale/locale_en-US.ini
  24. +7
    -2
      options/locale/locale_zh-CN.ini
  25. +10
    -2
      public/self/css/notebook/notebook.css
  26. +12
    -12
      public/self/dataset_preview.js
  27. +20
    -3
      routers/admin/cloudbrains.go
  28. +1
    -0
      routers/api/v1/api.go
  29. +10
    -2
      routers/api/v1/repo/cloudbrain.go
  30. +39
    -60
      routers/api/v1/repo/cloudbrain_dashboard.go
  31. +21
    -6
      routers/api/v1/repo/modelarts.go
  32. +8
    -8
      routers/repo/ai_model_manage.go
  33. +270
    -39
      routers/repo/cloudbrain.go
  34. +22
    -13
      routers/repo/grampus.go
  35. +40
    -13
      routers/repo/modelarts.go
  36. +76
    -8
      routers/repo/user_data_analysis.go
  37. +1
    -0
      routers/repo/view.go
  38. +2
    -1
      routers/routes/routes.go
  39. +26
    -2
      routers/search.go
  40. +6
    -0
      routers/user/home.go
  41. +3
    -3
      routers/user/profile.go
  42. +111
    -48
      templates/admin/cloudbrain/list.tmpl
  43. +1
    -1
      templates/admin/cloudbrain/search_dashboard.tmpl
  44. +2
    -2
      templates/admin/dataset/list.tmpl
  45. +5
    -0
      templates/base/head.tmpl
  46. +5
    -0
      templates/base/head_course.tmpl
  47. +5
    -0
      templates/base/head_fluid.tmpl
  48. +5
    -0
      templates/base/head_home.tmpl
  49. +4
    -2
      templates/base/head_navbar.tmpl
  50. +4
    -2
      templates/base/head_navbar_fluid.tmpl
  51. +4
    -2
      templates/base/head_navbar_home.tmpl
  52. +4
    -2
      templates/base/head_navbar_pro.tmpl
  53. +5
    -0
      templates/base/head_pro.tmpl
  54. +1
    -0
      templates/custom/select_dataset_train.tmpl
  55. +8
    -5
      templates/explore/dataset_list.tmpl
  56. +1
    -1
      templates/org/create.tmpl
  57. +5
    -5
      templates/repo/cloudbrain/benchmark/new.tmpl
  58. +9
    -1
      templates/repo/cloudbrain/benchmark/show.tmpl
  59. +129
    -106
      templates/repo/cloudbrain/inference/new.tmpl
  60. +9
    -1
      templates/repo/cloudbrain/inference/show.tmpl
  61. +21
    -0
      templates/repo/cloudbrain/new.tmpl
  62. +12
    -2
      templates/repo/cloudbrain/show.tmpl
  63. +75
    -142
      templates/repo/cloudbrain/trainjob/new.tmpl
  64. +9
    -1
      templates/repo/cloudbrain/trainjob/show.tmpl
  65. +1
    -1
      templates/repo/create.tmpl
  66. +3
    -2
      templates/repo/debugjob/index.tmpl
  67. +67
    -130
      templates/repo/grampus/trainjob/gpu/new.tmpl
  68. +81
    -116
      templates/repo/grampus/trainjob/npu/new.tmpl
  69. +0
    -1
      templates/repo/header.tmpl
  70. +2
    -2
      templates/repo/migrate.tmpl
  71. +88
    -57
      templates/repo/modelarts/inferencejob/new.tmpl
  72. +25
    -3
      templates/repo/modelarts/notebook/new.tmpl
  73. +12
    -2
      templates/repo/modelarts/notebook/show.tmpl
  74. +39
    -10
      templates/repo/modelarts/trainjob/new.tmpl
  75. +1
    -1
      templates/repo/modelarts/trainjob/show.tmpl
  76. +2
    -1
      templates/repo/modelmanage/index.tmpl
  77. +10
    -4
      templates/repo/view_file.tmpl
  78. +84
    -41
      templates/user/dashboard/cloudbrains.tmpl
  79. +12
    -10
      web_src/js/components/Model.vue
  80. +11
    -11
      web_src/js/components/dataset/selectDataset.vue
  81. +33
    -7
      web_src/js/components/images/Images.vue
  82. +3
    -0
      web_src/js/components/images/selectGrampusImages.vue
  83. +3
    -0
      web_src/js/components/images/selectImages.vue
  84. +26
    -12
      web_src/js/features/clipboard.js
  85. +7
    -3
      web_src/js/index.js
  86. +27
    -21
      web_src/less/_dataset.less
  87. +1
    -0
      web_src/less/openi.less

+ 1
- 0
.gitignore View File

@@ -55,6 +55,7 @@ coverage.all
!/custom/conf/templates
/custom/conf/app.ini
!/custom/conf/app.ini.sample
/custom/public/kanban
/data
/indexers
/log


+ 4
- 1
README.md View File

@@ -54,4 +54,7 @@
## 平台引用
如果本平台对您的科研工作提供了帮助,可在论文致谢中加入:
英文版:```Thanks for the support provided by OpenI Community (https://git.openi.org.cn).```
中文版:```感谢启智社区提供的技术支持(https://git.openi.org.cn)。```
中文版:```感谢启智社区提供的技术支持(https://git.openi.org.cn)。```

如果您的成果中引用了本平台,也欢迎在下述开源项目中提交您的成果信息:
https://git.openi.org.cn/OpenIOSSG/references

+ 155
- 4
models/cloudbrain.go View File

@@ -137,6 +137,8 @@ type Cloudbrain struct {
Type int `xorm:"INDEX"`
BenchmarkTypeID int
BenchmarkChildTypeID int
CardType string
Cluster string

VersionID int64 //版本id
VersionName string `xorm:"INDEX"` //当前版本
@@ -206,7 +208,16 @@ func (task *Cloudbrain) CorrectCreateUnix() {

func (task *Cloudbrain) IsTerminal() bool {
status := task.Status
return status == string(ModelArtsTrainJobCompleted) || status == string(ModelArtsTrainJobFailed) || status == string(ModelArtsTrainJobKilled) || status == string(ModelArtsStopped) || status == string(JobStopped) || status == string(JobFailed) || status == string(JobSucceeded)
return status == string(ModelArtsTrainJobCompleted) || status == string(ModelArtsTrainJobFailed) ||
status == string(ModelArtsTrainJobKilled) || status == string(ModelArtsStopped) ||
status == string(JobStopped) || status == string(JobFailed) ||
status == string(JobSucceeded) || status == GrampusStatusFailed ||
status == GrampusStatusSucceeded || status == GrampusStatusStopped
}
func (task *Cloudbrain) IsRunning() bool {
status := task.Status
return status == string(ModelArtsTrainJobRunning) || status == string(ModelArtsRunning) ||
status == string(JobRunning) || status == GrampusStatusRunning
}

func ConvertDurationToStr(duration int64) string {
@@ -1669,6 +1680,37 @@ func GetCloudbrainsNeededStopByUserID(userID int64) ([]*Cloudbrain, error) {
return cloudBrains, err
}

func GetWaittingTop() ([]*CloudbrainInfo, error) {
sess := x.NewSession()
defer sess.Close()
var cond = builder.NewCond()
cond = cond.And(
builder.Eq{"cloudbrain.status": string(JobWaiting)},
)
sess.OrderBy("cloudbrain.created_unix ASC limit 1")
cloudbrains := make([]*CloudbrainInfo, 0, 1)
if err := sess.Table(&Cloudbrain{}).Where(cond).
Find(&cloudbrains); err != nil {
log.Info("find error.")
}
return cloudbrains, nil
}
func GetModelartsReDebugTaskByJobId(jobID string) ([]*Cloudbrain, error) {
sess := x.NewSession()
defer sess.Close()
var cond = builder.NewCond()
cond = cond.And(
builder.Eq{"cloudbrain.job_id": jobID},
)
sess.OrderBy("cloudbrain.created_unix ASC limit 1")
cloudbrains := make([]*Cloudbrain, 0, 10)
if err := sess.Table(&Cloudbrain{}).Unscoped().Where(cond).
Find(&cloudbrains); err != nil {
log.Info("find error.")
}
return cloudbrains, nil
}

func GetCloudbrainsNeededStopByRepoID(repoID int64) ([]*Cloudbrain, error) {
cloudBrains := make([]*Cloudbrain, 0)
err := x.Cols("job_id", "status", "type", "job_type", "version_id", "start_time").Where("repo_id=? AND status !=?", repoID, string(JobStopped)).Find(&cloudBrains)
@@ -1918,7 +1960,8 @@ func CloudbrainAll(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, error) {
}

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"}))
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"}))
}

if len(opts.CloudbrainIDs) > 0 {
@@ -1956,7 +1999,8 @@ func CloudbrainAll(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, error) {
} else {
lowerKeyWord := strings.ToLower(opts.Keyword)

cond = cond.And(builder.Or(builder.Like{"LOWER(cloudbrain.job_name)", lowerKeyWord}, builder.Like{"LOWER(cloudbrain.display_job_name)", lowerKeyWord}, builder.Like{"`user`.lower_name", lowerKeyWord}))
cond = cond.And(builder.Or(builder.Like{"LOWER(cloudbrain.job_name)", lowerKeyWord},
builder.Like{"LOWER(cloudbrain.display_job_name)", lowerKeyWord}, builder.Like{"`user`.lower_name", lowerKeyWord}))
count, err = sess.Table(&Cloudbrain{}).Unscoped().Where(cond).
Join("left", "`user`", condition).Count(new(CloudbrainInfo))

@@ -2034,7 +2078,8 @@ func CloudbrainAllStatic(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, er
}
sess.OrderBy("cloudbrain.created_unix DESC")
cloudbrains := make([]*CloudbrainInfo, 0, setting.UI.IssuePagingNum)
if err := sess.Cols("status", "type", "job_type", "train_job_duration", "duration", "compute_resource", "created_unix", "start_time", "end_time").Table(&Cloudbrain{}).Unscoped().Where(cond).
if err := sess.Cols("status", "type", "job_type", "train_job_duration", "duration", "compute_resource",
"created_unix", "start_time", "end_time").Table(&Cloudbrain{}).Unscoped().Where(cond).
Find(&cloudbrains); err != nil {
return nil, 0, fmt.Errorf("Find: %v", err)
}
@@ -2089,6 +2134,112 @@ func GetDatasetInfo(uuidStr string) (map[string]DatasetInfo, string, error) {
return datasetInfos, datasetNames, nil
}

var (
SpecsMapInitFlag = false
CloudbrainDebugResourceSpecsMap map[int]*ResourceSpec
CloudbrainTrainResourceSpecsMap map[int]*ResourceSpec
CloudbrainInferenceResourceSpecsMap map[int]*ResourceSpec
CloudbrainBenchmarkResourceSpecsMap map[int]*ResourceSpec
CloudbrainSpecialResourceSpecsMap map[int]*ResourceSpec
GpuInfosMapInitFlag = false
CloudbrainDebugGpuInfosMap map[string]*GpuInfo
CloudbrainTrainGpuInfosMap map[string]*GpuInfo
CloudbrainInferenceGpuInfosMap map[string]*GpuInfo
CloudbrainBenchmarkGpuInfosMap map[string]*GpuInfo
CloudbrainSpecialGpuInfosMap map[string]*GpuInfo
)

func InitCloudbrainOneResourceSpecMap() {
if CloudbrainDebugResourceSpecsMap == nil || len(CloudbrainDebugResourceSpecsMap) == 0 {
t := ResourceSpecs{}
json.Unmarshal([]byte(setting.ResourceSpecs), &t)
CloudbrainDebugResourceSpecsMap = make(map[int]*ResourceSpec, len(t.ResourceSpec))
for _, spec := range t.ResourceSpec {
CloudbrainDebugResourceSpecsMap[spec.Id] = spec
}
}
if CloudbrainTrainResourceSpecsMap == nil || len(CloudbrainTrainResourceSpecsMap) == 0 {
t := ResourceSpecs{}
json.Unmarshal([]byte(setting.TrainResourceSpecs), &t)
CloudbrainTrainResourceSpecsMap = make(map[int]*ResourceSpec, len(t.ResourceSpec))
for _, spec := range t.ResourceSpec {
CloudbrainTrainResourceSpecsMap[spec.Id] = spec
}
}
if CloudbrainInferenceResourceSpecsMap == nil || len(CloudbrainInferenceResourceSpecsMap) == 0 {
t := ResourceSpecs{}
json.Unmarshal([]byte(setting.InferenceResourceSpecs), &t)
CloudbrainInferenceResourceSpecsMap = make(map[int]*ResourceSpec, len(t.ResourceSpec))
for _, spec := range t.ResourceSpec {
CloudbrainInferenceResourceSpecsMap[spec.Id] = spec
}
}
if CloudbrainBenchmarkResourceSpecsMap == nil || len(CloudbrainBenchmarkResourceSpecsMap) == 0 {
t := ResourceSpecs{}
json.Unmarshal([]byte(setting.BenchmarkResourceSpecs), &t)
CloudbrainBenchmarkResourceSpecsMap = make(map[int]*ResourceSpec, len(t.ResourceSpec))
for _, spec := range t.ResourceSpec {
CloudbrainBenchmarkResourceSpecsMap[spec.Id] = spec
}
}
if CloudbrainSpecialResourceSpecsMap == nil || len(CloudbrainSpecialResourceSpecsMap) == 0 {
t := SpecialPools{}
json.Unmarshal([]byte(setting.SpecialPools), &t)
for _, pool := range t.Pools {
CloudbrainSpecialResourceSpecsMap = make(map[int]*ResourceSpec, len(pool.ResourceSpec))
for _, spec := range pool.ResourceSpec {
CloudbrainSpecialResourceSpecsMap[spec.Id] = spec
}
}
}
SpecsMapInitFlag = true
}

func InitCloudbrainOneGpuInfoMap() {
if CloudbrainDebugGpuInfosMap == nil || len(CloudbrainDebugGpuInfosMap) == 0 {
t := GpuInfos{}
json.Unmarshal([]byte(setting.GpuTypes), &t)
CloudbrainDebugGpuInfosMap = make(map[string]*GpuInfo, len(t.GpuInfo))
for _, GpuInfo := range t.GpuInfo {
CloudbrainDebugGpuInfosMap[GpuInfo.Queue] = GpuInfo
}
}
if CloudbrainTrainGpuInfosMap == nil || len(CloudbrainTrainGpuInfosMap) == 0 {
t := GpuInfos{}
json.Unmarshal([]byte(setting.TrainGpuTypes), &t)
CloudbrainTrainGpuInfosMap = make(map[string]*GpuInfo, len(t.GpuInfo))
for _, GpuInfo := range t.GpuInfo {
CloudbrainTrainGpuInfosMap[GpuInfo.Queue] = GpuInfo
}
}
if CloudbrainInferenceGpuInfosMap == nil || len(CloudbrainInferenceGpuInfosMap) == 0 {
t := GpuInfos{}
json.Unmarshal([]byte(setting.InferenceGpuTypes), &t)
CloudbrainInferenceGpuInfosMap = make(map[string]*GpuInfo, len(t.GpuInfo))
for _, GpuInfo := range t.GpuInfo {
CloudbrainInferenceGpuInfosMap[GpuInfo.Queue] = GpuInfo
}
}
if CloudbrainBenchmarkGpuInfosMap == nil || len(CloudbrainBenchmarkGpuInfosMap) == 0 {
t := GpuInfos{}
json.Unmarshal([]byte(setting.BenchmarkGpuTypes), &t)
CloudbrainBenchmarkGpuInfosMap = make(map[string]*GpuInfo, len(t.GpuInfo))
for _, GpuInfo := range t.GpuInfo {
CloudbrainBenchmarkGpuInfosMap[GpuInfo.Queue] = GpuInfo
}
}
if CloudbrainSpecialGpuInfosMap == nil || len(CloudbrainSpecialGpuInfosMap) == 0 {
t := SpecialPools{}
json.Unmarshal([]byte(setting.SpecialPools), &t)
for _, pool := range t.Pools {
CloudbrainSpecialGpuInfosMap = make(map[string]*GpuInfo, len(pool.Pool))
for _, GpuInfo := range pool.Pool {
CloudbrainSpecialGpuInfosMap[GpuInfo.Queue] = GpuInfo
}
}
}
GpuInfosMapInitFlag = true
}
func GetNewestJobsByAiCenter() ([]int64, error) {
ids := make([]int64, 0)
return ids, x.


+ 5
- 15
models/cloudbrain_static.go View File

@@ -29,6 +29,11 @@ type TaskDetail struct {
RepoAlias string `json:"RepoAlias"`
RepoID int64 `json:"RepoID"`
IsDelete bool `json:"IsDelete"`
CardNum int `json:"CardNum"`
CardType string `json:"CardType"`
CardDuration string `json:"CardDuration"`
AiCenter string `json:"AiCenter"`
FlavorName string `json:"FlavorName"`
}

func GetDebugOnePeriodCount(beginTime time.Time, endTime time.Time) (int64, error) {
@@ -206,21 +211,6 @@ func GetAllStatusCloudBrain() map[string]int {
return cloudBrainStatusResult
}

func GetWaittingTop() ([]*CloudbrainInfo, error) {
sess := x.NewSession()
defer sess.Close()
var cond = builder.NewCond()
cond = cond.And(
builder.Eq{"cloudbrain.status": string(JobWaiting)},
)
sess.OrderBy("cloudbrain.created_unix ASC limit 10")
cloudbrains := make([]*CloudbrainInfo, 0, 10)
if err := sess.Table(&Cloudbrain{}).Where(cond).
Find(&cloudbrains); err != nil {
log.Info("find error.")
}
return cloudbrains, nil
}
func GetRunningTop() ([]*CloudbrainInfo, error) {
sess := x.NewSession()
defer sess.Close()


+ 14
- 10
models/dbsql/dataset_foreigntable_for_es.sql View File

@@ -158,16 +158,20 @@ DROP TRIGGER IF EXISTS es_update_dataset on public.dataset;
CREATE OR REPLACE FUNCTION public.update_dataset() RETURNS trigger AS
$def$
BEGIN
UPDATE public.dataset_es
SET description=NEW.description,
title=NEW.title,
category=NEW.category,
task=NEW.task,
download_times=NEW.download_times,
updated_unix=NEW.updated_unix,
file_name=(select array_to_string(array_agg(name order by created_unix desc),'-#,#-') from public.attachment where dataset_id=NEW.id and is_private=false),
file_desc=(select array_to_string(array_agg(description order by created_unix desc),'-#,#-') from public.attachment where dataset_id=NEW.id and is_private=false)
where id=NEW.id;
if (NEW.status=0) then
delete from public.dataset_es where id=NEW.id;
elsif (NEW.status=1) then
UPDATE public.dataset_es
SET description=NEW.description,
title=NEW.title,
category=NEW.category,
task=NEW.task,
download_times=NEW.download_times,
updated_unix=NEW.updated_unix,
file_name=(select array_to_string(array_agg(name order by created_unix desc),'-#,#-') from public.attachment where dataset_id=NEW.id and is_private=false),
file_desc=(select array_to_string(array_agg(description order by created_unix desc),'-#,#-') from public.attachment where dataset_id=NEW.id and is_private=false)
where id=NEW.id;
end if;
return new;
END
$def$


+ 1
- 1
models/dbsql/repo_foreigntable_for_es.sql View File

@@ -461,7 +461,7 @@ $def$

if not OLD.is_private and NEW.is_private then
delete from public.issue_es where repo_id=NEW.id;
delete from public.dataset_es where repo_id=NEW.id;
-- delete from public.dataset_es where repo_id=NEW.id;
delete from public.repository_es where id=NEW.id;
end if;



+ 8
- 7
models/repo.go View File

@@ -1603,13 +1603,6 @@ func updateRepository(e Engine, repo *Repository, visibilityChanged bool) (err e
if err != nil {
return err
}
//If repo has become private, we need set dataset and dataset_file to private
_, err = e.Where("repo_id = ? and status <> 2", repo.ID).Cols("status").Update(&Dataset{
Status: 0,
})
if err != nil {
return err
}

dataset, err := GetDatasetByRepo(repo)
if err != nil && !IsErrNotExist(err) {
@@ -1624,6 +1617,14 @@ func updateRepository(e Engine, repo *Repository, visibilityChanged bool) (err e
}
}

//If repo has become private, we need set dataset and dataset_file to private
_, err = e.Where("repo_id = ? and status <> 2", repo.ID).Cols("status").Update(&Dataset{
Status: 0,
})
if err != nil {
return err
}

} else {
//If repo has become public, we need set dataset to public
_, err = e.Where("repo_id = ? and status <> 2", repo.ID).Cols("status").Update(&Dataset{


+ 3
- 0
models/repo_activity_custom.go View File

@@ -238,6 +238,9 @@ func GetAllUserPublicRepoKPIStats(startTime time.Time, endTime time.Time) (map[s
CommitLines: 0,
}
}
if value.Email == "1250125907@qq.com" || value.Email == "peiyongyu-34@163.com" {
log.Info("repo path=" + repository.RepoPath())
}
authors[key].Commits += value.Commits
authors[key].CommitLines += value.CommitLines



+ 15
- 1
models/user_analysis_for_activity.go View File

@@ -6,6 +6,7 @@ import (

"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/timeutil"
"xorm.io/builder"
)

type UserBusinessAnalysisForActivity struct {
@@ -195,7 +196,7 @@ func queryPullRequestPublic(start_unix int64, end_unix int64, publicAllRepo map[
sess := x.NewSession()
defer sess.Close()
resultMap := make(map[int64]int)
cond := "pull_request.merged_unix>=" + fmt.Sprint(start_unix) + " and pull_request.merged_unix<=" + fmt.Sprint(end_unix)
cond := "issue.created_unix>=" + fmt.Sprint(start_unix) + " and issue.created_unix<=" + fmt.Sprint(end_unix)
count, err := sess.Table("issue").Join("inner", "pull_request", "issue.id=pull_request.issue_id").Where(cond).Count(new(Issue))
if err != nil {
log.Info("query issue error. return.")
@@ -435,3 +436,16 @@ func queryUserModelPublic(start_unix int64, end_unix int64, publicAllRepo map[in
}
return resultMap
}

func QueryUserLoginInfo(userIds []int64) []*UserLoginLog {
statictisSess := xStatistic.NewSession()
defer statictisSess.Close()
var cond = builder.NewCond()
cond = cond.And(builder.In("u_id", userIds))
statictisSess.Select("*").Table(new(UserLoginLog)).Where(cond)
loginList := make([]*UserLoginLog, 0)

statictisSess.Find(&loginList)

return loginList
}

+ 43
- 5
models/user_business_analysis.go View File

@@ -110,9 +110,9 @@ type UserBusinessAnalysisAll struct {
}

type UserBusinessAnalysis struct {
ID int64 `xorm:"pk"`
CountDate int64 `xorm:"pk"`
ID int64 `xorm:"pk"`
DataDate string `xorm:"pk"`
CountDate int64 `xorm:"NULL"`

//action :ActionMergePullRequest // 11
CodeMergeCount int `xorm:"NOT NULL DEFAULT 0"`
@@ -171,8 +171,6 @@ type UserBusinessAnalysis struct {
//user
Name string `xorm:"NOT NULL"`

DataDate string `xorm:"NULL"`

CloudBrainTaskNum int `xorm:"NOT NULL DEFAULT 0"`
GpuDebugJob int `xorm:"NOT NULL DEFAULT 0"`
NpuDebugJob int `xorm:"NOT NULL DEFAULT 0"`
@@ -411,6 +409,42 @@ func QueryUserStaticDataAll(opts *UserBusinessAnalysisQueryOptions) ([]*UserBusi
return userBusinessAnalysisReturnList, allCount
}

func QueryDataForUserDefineFromDb(opts *UserBusinessAnalysisQueryOptions, key string) ([]*UserBusinessAnalysis, int64) {
statictisSess := xStatistic.NewSession()
defer statictisSess.Close()
cond := "data_date='" + key + "'"
allCount, err := statictisSess.Where(cond).Count(new(UserBusinessAnalysis))
if err == nil {
if allCount > 0 {
userBusinessAnalysisList := make([]*UserBusinessAnalysis, 0)
if err := statictisSess.Table("user_business_analysis").Where(cond).OrderBy("id desc").Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).
Find(&userBusinessAnalysisList); err != nil {
return nil, 0
}
return userBusinessAnalysisList, allCount
}
}
return nil, 0
}

func WriteDataToDb(dataList []*UserBusinessAnalysis, key string) {
statictisSess := xStatistic.NewSession()
defer statictisSess.Close()
log.Info("write to db, size=" + fmt.Sprint(len(dataList)))
userBusinessAnalysisList := make([]*UserBusinessAnalysis, 0)
for _, data := range dataList {
data.DataDate = key
userBusinessAnalysisList = append(userBusinessAnalysisList, data)
if len(userBusinessAnalysisList) > BATCH_INSERT_SIZE {
statictisSess.Insert(userBusinessAnalysisList)
userBusinessAnalysisList = make([]*UserBusinessAnalysis, 0)
}
}
if len(userBusinessAnalysisList) > 0 {
statictisSess.Insert(userBusinessAnalysisList)
}
}

func QueryUserStaticDataForUserDefine(opts *UserBusinessAnalysisQueryOptions, wikiCountMap map[string]int) ([]*UserBusinessAnalysis, int64) {
log.Info("start to count other user info data")
sess := x.NewSession()
@@ -954,6 +988,9 @@ func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time,
statictisSess := xStatistic.NewSession()
defer statictisSess.Close()

log.Info("truncate all data from table:user_business_analysis ")
statictisSess.Exec("TRUNCATE TABLE user_business_analysis")

cond := "type != 1"
count, err := sess.Where(cond).Count(new(User))
if err != nil {
@@ -1103,6 +1140,7 @@ func updateNewUserAcitivity(currentUserActivity map[int64]map[int64]int64, userA
",activate_regist_user=" + fmt.Sprint(useMetrics.ActivateRegistUser) +
",not_activate_regist_user=" + fmt.Sprint(useMetrics.CurrentDayRegistUser-useMetrics.ActivateRegistUser) +
",current_day_regist_user=" + fmt.Sprint(useMetrics.CurrentDayRegistUser) +
",activate_index=" + fmt.Sprint(float64(useMetrics.ActivateRegistUser)/float64(useMetrics.CurrentDayRegistUser)) +
",data_date='" + time.Unix(key, 0).Format("2006-01-02") + "'" +
" where count_date=" + fmt.Sprint(key)



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

@@ -23,6 +23,7 @@ type CreateCloudBrainForm struct {
BootFile string `form:"boot_file"`
Params string `form:"run_para_list"`
BranchName string `form:"branch_name"`
DatasetName string `form:"dataset_name"`
}

type CommitImageCloudBrainForm struct {
@@ -70,6 +71,7 @@ type CreateCloudBrainInferencForm struct {
ModelVersion string `form:"model_version" binding:"Required"`
CkptName string `form:"ckpt_name" binding:"Required"`
LabelName string `form:"label_names" binding:"Required"`
DatasetName string `form:"dataset_name"`
}

func (f *CreateCloudBrainForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {


+ 1
- 0
modules/auth/grampus.go View File

@@ -19,6 +19,7 @@ type CreateGrampusTrainJobForm struct {
EngineName string `form:"engine_name" binding:"Required"`
WorkServerNumber int `form:"work_server_number" binding:"Required"`
Image string `form:"image"`
DatasetName string `form:"dataset_name"`
}

func (f *CreateGrampusTrainJobForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {


+ 46
- 0
modules/auth/wechat/client.go View File

@@ -19,6 +19,7 @@ const (
ACCESS_TOKEN_PATH = "/cgi-bin/token"
QR_CODE_PATH = "/cgi-bin/qrcode/create"
GET_MATERIAL_PATH = "/cgi-bin/material/batchget_material"
SEND_TEMPLATE_PATH = "/cgi-bin/message/template/send"
ACTION_QR_STR_SCENE = "QR_STR_SCENE"

ERR_CODE_ACCESSTOKEN_EXPIRE = 42001
@@ -41,12 +42,33 @@ type QRCodeRequest struct {
Action_info ActionInfo `json:"action_info"`
Expire_seconds int `json:"expire_seconds"`
}

type MaterialRequest struct {
Type string `json:"type"`
Offset int `json:"offset"`
Count int `json:"count"`
}

type TemplateMsgRequest struct {
ToUser string `json:"touser"`
TemplateId string `json:"template_id"`
Url string `json:"url"`
ClientMsgId string `json:"client_msg_id"`
Data interface{} `json:"data"`
}
type TemplateValue struct {
Value string `json:"value"`
Color string `json:"color"`
}

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

type ActionInfo struct {
Scene Scene `json:"scene"`
}
@@ -161,3 +183,27 @@ func getErrorCodeFromResponse(r *resty.Response) int {
c, _ := strconv.Atoi(fmt.Sprint(code))
return c
}

func sendTemplateMsg(req TemplateMsgRequest) (error, bool) {
client := getWechatRestyClient()

bodyJson, _ := json.Marshal(req)
r, err := client.R().
SetHeader("Content-Type", "application/json").
SetQueryParam("access_token", GetWechatAccessToken()).
SetBody(bodyJson).
Post(setting.WechatApiHost + SEND_TEMPLATE_PATH)
if err != nil {
log.Error("sendTemplateMsg,e=%v", err)
return nil, false
}
a := r.Body()
resultMap := make(map[string]interface{}, 0)
json.Unmarshal(a, &resultMap)
errcode := resultMap["errcode"]
log.Info("sendTemplateMsg,%v", r)
if errcode == fmt.Sprint(ERR_CODE_ACCESSTOKEN_EXPIRE) || errcode == fmt.Sprint(ERR_CODE_ACCESSTOKEN_INVALID) {
return nil, true
}
return nil, false
}

+ 145
- 0
modules/auth/wechat/template.go View File

@@ -0,0 +1,145 @@
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"
)

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

func SendCloudbrainStartedMsg(operateType JobOperateType, cloudbrain models.Cloudbrain) 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 == "" {
return nil
}

openId := models.GetUserWechatOpenId(cloudbrain.UserID)
if openId == "" {
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,
}
err, retryFlag := sendTemplateMsg(req)
if retryFlag {
log.Info("retrySendCloudbrainTemplateMsg calling")
refreshAccessToken()
err, _ = sendTemplateMsg(req)
if err != nil {
log.Error("SendCloudbrainStartedMsg err. %v", err)
return err
}
return nil
}
if err != nil {
log.Error("SendCloudbrainStartedMsg err. %v", err)
return err
}
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 ""
}

+ 24
- 20
modules/cloudbrain/cloudbrain.go View File

@@ -326,7 +326,7 @@ func GenerateTask(req GenerateCloudBrainTaskReq) error {
ReadOnly: true,
},
})
} else {
} else if len(req.DatasetInfos) > 1 {
for _, dataset := range req.DatasetInfos {
volumes = append(volumes, models.Volume{
HostPath: models.StHostPath{
@@ -466,11 +466,14 @@ func RestartTask(ctx *context.Context, task *models.Cloudbrain, newID *string) e
log.Error("no such resourceSpecId(%d)", task.ResourceSpecId, ctx.Data["MsgID"])
return errors.New("no such resourceSpec")
}

datasetInfos, _, err := models.GetDatasetInfo(task.Uuid)
if err != nil {
log.Error("GetDatasetInfo failed:%v", err, ctx.Data["MsgID"])
return err
var datasetInfos map[string]models.DatasetInfo
if task.Uuid != "" {
var err error
datasetInfos, _, err = models.GetDatasetInfo(task.Uuid)
if err != nil {
log.Error("GetDatasetInfo failed:%v", err, ctx.Data["MsgID"])
return err
}
}

volumes := []models.Volume{
@@ -510,24 +513,25 @@ func RestartTask(ctx *context.Context, task *models.Cloudbrain, newID *string) e
},
},
}

if len(datasetInfos) == 1 {
volumes = append(volumes, models.Volume{
HostPath: models.StHostPath{
Path: datasetInfos[task.Uuid].DataLocalPath,
MountPath: DataSetMountPath,
ReadOnly: true,
},
})
} else {
for _, dataset := range datasetInfos {
if datasetInfos != nil {
if len(datasetInfos) == 1 {
volumes = append(volumes, models.Volume{
HostPath: models.StHostPath{
Path: dataset.DataLocalPath,
MountPath: DataSetMountPath + "/" + dataset.Name,
Path: datasetInfos[task.Uuid].DataLocalPath,
MountPath: DataSetMountPath,
ReadOnly: true,
},
})
} else {
for _, dataset := range datasetInfos {
volumes = append(volumes, models.Volume{
HostPath: models.StHostPath{
Path: dataset.DataLocalPath,
MountPath: DataSetMountPath + "/" + dataset.Name,
ReadOnly: true,
},
})
}
}
}

@@ -547,7 +551,7 @@ func RestartTask(ctx *context.Context, task *models.Cloudbrain, newID *string) e
GPUNumber: resourceSpec.GpuNum,
MemoryMB: resourceSpec.MemMiB,
ShmMB: resourceSpec.ShareMemMiB,
Command: GetCloudbrainDebugCommand(),//Command,
Command: GetCloudbrainDebugCommand(), //Command,
NeedIBDevice: false,
IsMainRole: false,
UseNNI: false,


+ 2
- 1
modules/context/context.go View File

@@ -6,7 +6,6 @@
package context

import (
"code.gitea.io/gitea/routers/notice"
"html"
"html/template"
"io"
@@ -16,6 +15,8 @@ import (
"strings"
"time"

"code.gitea.io/gitea/routers/notice"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/auth"
"code.gitea.io/gitea/modules/base"


+ 1
- 1
modules/git/repo_stats_custom.go View File

@@ -62,7 +62,7 @@ func GetUserKPIStats(repoPath string, startTime time.Time, endTime time.Time) (m

after := startTime.Format(time.RFC3339)
until := endTime.Format(time.RFC3339)
args := []string{"log", "--numstat", "--no-merges", "--branches=*", "--pretty=format:---%n%h%n%an%n%ae%n", "--date=iso", fmt.Sprintf("--after='%s'", after), fmt.Sprintf("--until=='%s'", until)}
args := []string{"log", "--numstat", "--no-merges", "--branches=*", "--pretty=format:---%n%h%n%an%n%ae%n", "--date=iso", fmt.Sprintf("--after='%s'", after), fmt.Sprintf("--until='%s'", until)}
stdout, err := NewCommand(args...).RunInDirBytes(repoPath)
if err != nil {
return nil, err


+ 2
- 0
modules/notification/base/notifier.go View File

@@ -56,4 +56,6 @@ type Notifier interface {
NotifySyncDeleteRef(doer *models.User, repo *models.Repository, refType, refFullName string)

NotifyOtherTask(doer *models.User, repo *models.Repository, id string, name string, optype models.ActionType)

NotifyChangeCloudbrainStatus(cloudbrain *models.Cloudbrain, oldStatus string)
}

+ 4
- 0
modules/notification/base/null.go View File

@@ -158,3 +158,7 @@ func (*NullNotifier) NotifySyncDeleteRef(doer *models.User, repo *models.Reposit
func (*NullNotifier) NotifyOtherTask(doer *models.User, repo *models.Repository, id string, name string, optype models.ActionType) {

}

func (*NullNotifier) NotifyChangeCloudbrainStatus(cloudbrain *models.Cloudbrain, oldStatus string) {

}

+ 9
- 0
modules/notification/notification.go View File

@@ -12,6 +12,7 @@ import (
"code.gitea.io/gitea/modules/notification/mail"
"code.gitea.io/gitea/modules/notification/ui"
"code.gitea.io/gitea/modules/notification/webhook"
wechatNotifier "code.gitea.io/gitea/modules/notification/wechat"
"code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/setting"
)
@@ -35,6 +36,7 @@ func NewContext() {
RegisterNotifier(indexer.NewNotifier())
RegisterNotifier(webhook.NewNotifier())
RegisterNotifier(action.NewNotifier())
RegisterNotifier(wechatNotifier.NewNotifier())
}

// NotifyUploadAttachment notifies attachment upload message to notifiers
@@ -269,3 +271,10 @@ func NotifySyncDeleteRef(pusher *models.User, repo *models.Repository, refType,
notifier.NotifySyncDeleteRef(pusher, repo, refType, refFullName)
}
}

// NotifyChangeCloudbrainStatus
func NotifyChangeCloudbrainStatus(cloudbrain *models.Cloudbrain, oldStatus string) {
for _, notifier := range notifiers {
notifier.NotifyChangeCloudbrainStatus(cloudbrain, oldStatus)
}
}

+ 44
- 0
modules/notification/wechat/wechat.go View File

@@ -0,0 +1,44 @@
// Copyright 2019 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package wechat

import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/auth/wechat"
"code.gitea.io/gitea/modules/notification/base"
"code.gitea.io/gitea/modules/setting"
)

type wechatNotifier struct {
base.NullNotifier
}

var (
_ base.Notifier = &wechatNotifier{}
)

// NewNotifier create a new wechatNotifier notifier
func NewNotifier() base.Notifier {
return &wechatNotifier{}
}

func (*wechatNotifier) NotifyChangeCloudbrainStatus(cloudbrain *models.Cloudbrain, oldStatus string) {
operateType := wechat.GetJobOperateTypeFromCloudbrainStatus(cloudbrain)
if operateType == "" {
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
}
}
}
}

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

@@ -583,6 +583,10 @@ var (
TreePathOfAutoMsgReply string
TreePathOfSubscribe string

//wechat template msg config
CloudbrainStartedTemplateId string
CloudbrainStartedNotifyList []string

//nginx proxy
PROXYURL string
RadarMap = struct {
@@ -1434,7 +1438,7 @@ func NewContext() {
WechatApiHost = sec.Key("HOST").MustString("https://api.weixin.qq.com")
WechatApiTimeoutSeconds = sec.Key("TIMEOUT_SECONDS").MustInt(3)
WechatAppId = sec.Key("APP_ID").MustString("wxba77b915a305a57d")
WechatAppSecret = sec.Key("APP_SECRET").MustString("e48e13f315adc32749ddc7057585f198")
WechatAppSecret = sec.Key("APP_SECRET").MustString("")
WechatQRCodeExpireSeconds = sec.Key("QR_CODE_EXPIRE_SECONDS").MustInt(120)
WechatAuthSwitch = sec.Key("AUTH_SWITCH").MustBool(true)
UserNameOfWechatReply = sec.Key("AUTO_REPLY_USER_NAME").MustString("OpenIOSSG")
@@ -1442,6 +1446,8 @@ func NewContext() {
RefNameOfWechatReply = sec.Key("AUTO_REPLY_REF_NAME").MustString("master")
TreePathOfAutoMsgReply = sec.Key("AUTO_REPLY_TREE_PATH").MustString("wechat/auto_reply.json")
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"), ",")

SetRadarMapConfig()



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

@@ -1007,7 +1007,7 @@ cloudbrain.time.starttime=Start run time
cloudbrain.time.endtime=End run time
cloudbrain.datasetdownload=Dataset download url
model_manager = Model
model_noright=No right
model_noright=You have no right to do the operation.
model_rename=Duplicate model name, please modify model name.

date=Date
@@ -1098,6 +1098,9 @@ modelarts.createtime=CreateTime
modelarts.version_nums = Version Nums
modelarts.version = Version
modelarts.computing_resources=compute Resources
modelarts.ai_center=Ai Center
modelarts.card_type=Card Type
modelarts.cluster=Cluster
modelarts.notebook=Debug Task
modelarts.train_job=Train Task
modelarts.train_job.new_debug= New Debug Task
@@ -1225,7 +1228,7 @@ model.manage.create_new_convert_task=Create Model Transformation Task
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.
modelconvert.manage.no_operate_right=No operation permission.
modelconvert.manage.no_operate_right=You have no right to do the operation.

grampus.train_job.ai_center = AI Center
grampus.dataset_path_rule = The code is storaged in /cache/code;the dataset is storaged in /cache/dataset;and please put your model into /cache/output, then you can download it online。


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

@@ -1006,7 +1006,7 @@ datasets.desc=数据集功能
cloudbrain_helper=使用GPU/NPU资源,开启Notebook、模型训练任务等

model_manager = 模型
model_noright=无权限操作
model_noright=您没有操作权限。
model_rename=模型名称重复,请修改模型名称


@@ -1108,6 +1108,9 @@ modelarts.deletetime=删除时间
modelarts.version_nums=版本数
modelarts.version=版本
modelarts.computing_resources=计算资源
modelarts.ai_center=智算中心
modelarts.card_type=卡类型
modelarts.cluster=集群
modelarts.notebook=调试任务
modelarts.train_job=训练任务
modelarts.train_job.new_debug=新建调试任务
@@ -1237,7 +1240,7 @@ model.manage.create_new_convert_task=创建模型转换任务
modelconvert.manage.create_error1=相同的名称模型转换任务已经存在。
modelconvert.manage.create_error2=只能创建一个正在运行的模型转换任务。
modelconvert.manage.model_not_exist=选择的模型不存在。
modelconvert.manage.no_operate_right=操作权限。
modelconvert.manage.no_operate_right=您没有操作权限。

grampus.train_job.ai_center=智算中心
grampus.dataset_path_rule = 训练脚本存储在/cache/code中,数据集存储在/cache/dataset中,训练输出请存储在/cache/output中以供后续下载。
@@ -3119,6 +3122,8 @@ select_dataset = 选择数据集
specification = 规格
select_specification = 选择资源规格
description = 描述
card_duration = 运行卡时
card_type = 卡类型
wrong_specification=您目前不能使用这个资源规格,请选择其他资源规格。

job_name_rule = 请输入字母、数字、_和-,最长64个字符,且不能以中划线(-)结尾。


+ 10
- 2
public/self/css/notebook/notebook.css View File

@@ -1,6 +1,7 @@
.nb-notebook {
line-height: 1.5;
margin-left: 7em;
margin-left: 6em;
}

.nb-stdout, .nb-stderr {
@@ -15,6 +16,7 @@

.nb-cell + .nb-cell {
margin-top: 0.5em;
max-width: 100%;
}

.nb-output table {
@@ -40,6 +42,11 @@
padding-left: 1em;
}

.nb-notebook img {
max-width: 80%;
padding: 3px;
}

.nb-cell {
position: relative;
}
@@ -60,7 +67,8 @@
}

.nb-output img {
max-width: 100%;
max-width: 80%;
padding: 3px;
}

.nb-output:before, .nb-input:before {


+ 12
- 12
public/self/dataset_preview.js View File

@@ -123,13 +123,13 @@ function loadimg(uuid,filename){
function loadimg(){
var length = labeltastresult[fileindex].pic_image_field.length;
 if(labeltastresult[fileindex].pic_image_field.substring(length - 5) == ".json" 
     || labeltastresult[fileindex].pic_image_field.substring(length - 4) == ".xml"
     || labeltastresult[fileindex].pic_image_field.substring(length - 4) == ".txt"
     || labeltastresult[fileindex].pic_image_field.substring(length - 4) == ".csv"
     || labeltastresult[fileindex].pic_image_field.substring(length - 3) == ".md"
     || labeltastresult[fileindex].pic_image_field.substring(length - 3) == ".py"
     || labeltastresult[fileindex].pic_image_field.substring(length - 3) == ".sh"){
 if(labeltastresult[fileindex].pic_image_field.substring(length - 5).toLowerCase() == ".json" 
     || labeltastresult[fileindex].pic_image_field.substring(length - 4).toLowerCase() == ".xml"
     || labeltastresult[fileindex].pic_image_field.substring(length - 4).toLowerCase() == ".txt"
     || labeltastresult[fileindex].pic_image_field.substring(length - 4).toLowerCase() == ".csv"
     || labeltastresult[fileindex].pic_image_field.substring(length - 3).toLowerCase() == ".md"
     || labeltastresult[fileindex].pic_image_field.substring(length - 3).toLowerCase() == ".py"
     || labeltastresult[fileindex].pic_image_field.substring(length - 3).toLowerCase() == ".sh"){
//文本
canvas.style.display="none";
@@ -138,11 +138,11 @@ function loadimg(){
$('#textcontent').height(canvas.height-40)
$("#textcontent").text(textContent);
}else{
if(labeltastresult[fileindex].pic_image_field.substring(length - 5) == ".jpeg" 
    || labeltastresult[fileindex].pic_image_field.substring(length - 4) == ".jpg"
    || labeltastresult[fileindex].pic_image_field.substring(length - 4) == ".bmp"
    || labeltastresult[fileindex].pic_image_field.substring(length - 4) == ".gif"
    || labeltastresult[fileindex].pic_image_field.substring(length - 4) == ".png"){
if(labeltastresult[fileindex].pic_image_field.substring(length - 5).toLowerCase() == ".jpeg" 
    || labeltastresult[fileindex].pic_image_field.substring(length - 4).toLowerCase() == ".jpg"
    || labeltastresult[fileindex].pic_image_field.substring(length - 4).toLowerCase() == ".bmp"
    || labeltastresult[fileindex].pic_image_field.substring(length - 4).toLowerCase() == ".gif"
    || labeltastresult[fileindex].pic_image_field.substring(length - 4).toLowerCase() == ".png"){
canvas.style.display="block";
document.getElementById("textcontent").style.display="none";
img.src = ip + "/getgiteaimage?uuid=" + dataset_id + "&filename=" + labeltastresult[fileindex].pic_image_field;


+ 20
- 3
routers/admin/cloudbrains.go View File

@@ -10,6 +10,7 @@ import (
"github.com/360EntSecGroup-Skylar/excelize/v2"

"code.gitea.io/gitea/modules/modelarts"
"code.gitea.io/gitea/routers/repo"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/base"
@@ -89,6 +90,10 @@ func CloudBrains(ctx *context.Context) {
ciTasks[i].CanDebug = true
ciTasks[i].CanDel = true
ciTasks[i].Cloudbrain.ComputeResource = task.ComputeResource
ciTasks[i].Cloudbrain.AiCenter = repo.GetCloudbrainAiCenter(task.Cloudbrain, ctx)
_, cardType, _ := repo.GetCloudbrainCardNumAndType(task.Cloudbrain)
ciTasks[i].Cloudbrain.CardType = cardType
ciTasks[i].Cloudbrain.Cluster = repo.GetCloudbrainCluster(task.Cloudbrain, ctx)
}

pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, getTotalPage(count, setting.UI.IssuePagingNum))
@@ -188,11 +193,19 @@ func DownloadCloudBrains(ctx *context.Context) {
}

func allValues(row int, rs *models.CloudbrainInfo, ctx *context.Context) map[string]string {
return map[string]string{getCellName("A", row): rs.DisplayJobName, getCellName("B", row): rs.JobType, getCellName("C", row): rs.Status, getCellName("D", row): time.Unix(int64(rs.Cloudbrain.CreatedUnix), 0).Format(CREATE_TIME_FORMAT), getCellName("E", row): getDurationTime(rs),
getCellName("F", row): rs.ComputeResource, getCellName("G", row): rs.Name, getCellName("H", row): getRepoPathName(rs), getCellName("I", row): rs.JobName,
return map[string]string{getCellName("A", row): rs.DisplayJobName, getCellName("B", row): repo.GetCloudbrainCluster(rs.Cloudbrain, ctx),
getCellName("C", row): rs.JobType, getCellName("D", row): rs.Status, getCellName("E", row): time.Unix(int64(rs.Cloudbrain.CreatedUnix), 0).Format(CREATE_TIME_FORMAT),
getCellName("F", row): getDurationTime(rs), getCellName("G", row): rs.ComputeResource,
getCellName("H", row): repo.GetCloudbrainAiCenter(rs.Cloudbrain, ctx), getCellName("I", row): getCloudbrainCardType(rs),
getCellName("J", row): rs.Name, getCellName("K", row): getRepoPathName(rs), getCellName("L", row): rs.JobName,
}
}

func getCloudbrainCardType(rs *models.CloudbrainInfo) string {
_, cardType, _ := repo.GetCloudbrainCardNumAndType(rs.Cloudbrain)
return cardType
}

func getRepoPathName(rs *models.CloudbrainInfo) string {
if rs.Repo != nil {
return rs.Repo.OwnerName + "/" + rs.Repo.Alias
@@ -225,7 +238,11 @@ func getTotalPage(total int64, pageSize int) int {

func allHeader(ctx *context.Context) map[string]string {

return map[string]string{"A1": ctx.Tr("repo.cloudbrain_task"), "B1": ctx.Tr("repo.cloudbrain_task_type"), "C1": ctx.Tr("repo.modelarts.status"), "D1": ctx.Tr("repo.modelarts.createtime"), "E1": ctx.Tr("repo.modelarts.train_job.dura_time"), "F1": ctx.Tr("repo.modelarts.computing_resources"), "G1": ctx.Tr("repo.cloudbrain_creator"), "H1": ctx.Tr("repo.repo_name"), "I1": ctx.Tr("repo.cloudbrain_task_name")}
return map[string]string{"A1": ctx.Tr("repo.cloudbrain_task"), "B1": ctx.Tr("repo.modelarts.cluster"),
"C1": ctx.Tr("repo.cloudbrain_task_type"), "D1": ctx.Tr("repo.modelarts.status"), "E1": ctx.Tr("repo.modelarts.createtime"),
"F1": ctx.Tr("repo.modelarts.train_job.dura_time"), "G1": ctx.Tr("repo.modelarts.computing_resources"),
"H1": ctx.Tr("repo.modelarts.ai_center"), "I1": ctx.Tr("repo.modelarts.card_type"), "J1": ctx.Tr("repo.cloudbrain_creator"),
"K1": ctx.Tr("repo.repo_name"), "L1": ctx.Tr("repo.cloudbrain_task_name")}

}



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

@@ -571,6 +571,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Get("/query_user_yesterday", operationReq, repo_ext.QueryUserStaticYesterday)
m.Get("/query_user_all", operationReq, repo_ext.QueryUserStaticAll)
m.Get("/query_user_activity", operationReq, repo_ext.QueryUserActivity)
m.Get("/query_user_login", operationReq, repo_ext.QueryUserLoginInfo)
//cloudbrain board
m.Group("/cloudbrainboard", func() {
m.Get("/downloadAll", repo.DownloadCloudBrainBoard)


+ 10
- 2
routers/api/v1/repo/cloudbrain.go View File

@@ -6,6 +6,7 @@
package repo

import (
"code.gitea.io/gitea/modules/notification"
"encoding/json"
"net/http"
"sort"
@@ -74,7 +75,7 @@ func GetCloudbrainTask(ctx *context.APIContext) {
log.Error("ConvertToJobResultPayload failed:", err)
return
}
oldStatus := job.Status
job.Status = result.JobStatus.State
taskRoles := result.TaskRoles
taskRes, _ := models.ConvertToTaskPod(taskRoles[cloudbrain.SubTaskName].(map[string]interface{}))
@@ -86,6 +87,9 @@ func GetCloudbrainTask(ctx *context.APIContext) {

if result.JobStatus.State != string(models.JobWaiting) {
models.ParseAndSetDurationFromCloudBrainOne(result, job)
if oldStatus != job.Status {
notification.NotifyChangeCloudbrainStatus(job, oldStatus)
}
err = models.UpdateJob(job)
if err != nil {
log.Error("UpdateJob failed:", err)
@@ -99,6 +103,7 @@ func GetCloudbrainTask(ctx *context.APIContext) {
"SubState": result.JobStatus.SubState,
"CreatedTime": time.Unix(result.JobStatus.CreatedTime/1000, 0).Format("2006-01-02 15:04:05"),
"CompletedTime": time.Unix(result.JobStatus.CompletedTime/1000, 0).Format("2006-01-02 15:04:05"),
"JobDuration": job.TrainJobDuration,
})

}
@@ -123,7 +128,7 @@ func GetCloudBrainInferenceJob(ctx *context.APIContext) {
log.Error("ConvertToJobResultPayload failed:", err)
return
}
oldStatus := job.Status
job.Status = result.JobStatus.State
if result.JobStatus.State != string(models.JobWaiting) && result.JobStatus.State != string(models.JobFailed) {
taskRoles := result.TaskRoles
@@ -136,6 +141,9 @@ func GetCloudBrainInferenceJob(ctx *context.APIContext) {

if result.JobStatus.State != string(models.JobWaiting) {
models.ParseAndSetDurationFromCloudBrainOne(result, job)
if oldStatus != job.Status {
notification.NotifyChangeCloudbrainStatus(job, oldStatus)
}
err = models.UpdateJob(job)
if err != nil {
log.Error("UpdateJob failed:", err)


+ 39
- 60
routers/api/v1/repo/cloudbrain_dashboard.go View File

@@ -10,6 +10,7 @@ import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/routers/repo"
"github.com/360EntSecGroup-Skylar/excelize/v2"
)

@@ -735,6 +736,7 @@ func GetCloudbrainsDetailData(ctx *context.Context) {

var taskDetail models.TaskDetail
taskDetail.ID = ciTasks[i].Cloudbrain.ID
taskDetail.JobID = ciTasks[i].Cloudbrain.JobID
taskDetail.JobName = ciTasks[i].JobName
taskDetail.DisplayJobName = ciTasks[i].DisplayJobName
taskDetail.Status = ciTasks[i].Status
@@ -751,46 +753,12 @@ func GetCloudbrainsDetailData(ctx *context.Context) {
taskDetail.RepoName = ciTasks[i].Repo.OwnerName + "/" + ciTasks[i].Repo.Name
taskDetail.RepoAlias = ciTasks[i].Repo.OwnerName + "/" + ciTasks[i].Repo.Alias
}
if ciTasks[i].Cloudbrain.Status == string(models.JobWaiting) {
if ciTasks[i].Cloudbrain.DeletedAt != nilTime {
WaitTimeInt := ciTasks[i].Cloudbrain.UpdatedUnix.AsTime().Unix() - ciTasks[i].Cloudbrain.CreatedUnix.AsTime().Unix()
taskDetail.WaitTime = models.ConvertDurationToStr(WaitTimeInt)
if WaitTimeInt < 0 {
taskDetail.WaitTime = "00:00:00"
}
} else {
if ciTasks[i].Cloudbrain.StartTime.AsTime().Unix() == 0 {
WaitTimeInt := time.Now().Unix() - ciTasks[i].Cloudbrain.CreatedUnix.AsTime().Unix()
taskDetail.WaitTime = models.ConvertDurationToStr(WaitTimeInt)
if WaitTimeInt < 0 {
taskDetail.WaitTime = "00:00:00"
}
} else {
WaitTimeInt := ciTasks[i].Cloudbrain.StartTime.AsTime().Unix() - ciTasks[i].Cloudbrain.CreatedUnix.AsTime().Unix()
taskDetail.WaitTime = models.ConvertDurationToStr(WaitTimeInt)
if WaitTimeInt < 0 {
taskDetail.WaitTime = "00:00:00"
}
}
}
} else if ciTasks[i].Cloudbrain.Status == string(models.JobStopped) && ciTasks[i].Cloudbrain.StartTime.AsTime().Unix() == 0 {
WaitTimeInt := ciTasks[i].Cloudbrain.EndTime.AsTime().Unix() - ciTasks[i].Cloudbrain.CreatedUnix.AsTime().Unix()
taskDetail.WaitTime = models.ConvertDurationToStr(WaitTimeInt)
if WaitTimeInt < 0 {
taskDetail.WaitTime = "00:00:00"

}
} else {
WaitTimeInt := ciTasks[i].Cloudbrain.StartTime.AsTime().Unix() - ciTasks[i].Cloudbrain.CreatedUnix.AsTime().Unix()
taskDetail.WaitTime = models.ConvertDurationToStr(WaitTimeInt)
if WaitTimeInt < 0 {
taskDetail.WaitTime = "00:00:00"
}
}
taskDetail.CardNum, taskDetail.CardType, _ = repo.GetCloudbrainCardNumAndType(ciTasks[i].Cloudbrain)
taskDetail.CardDuration = repo.GetCloudbrainCardDuration(ciTasks[i].Cloudbrain)
taskDetail.AiCenter = repo.GetCloudbrainAiCenter(ciTasks[i].Cloudbrain, ctx)
taskDetail.FlavorName, _ = repo.GetCloudbrainFlavorName(ciTasks[i].Cloudbrain)

if ciTasks[i].Cloudbrain.Type == models.TypeCloudBrainTwo || (ciTasks[i].Cloudbrain.Type == models.TypeCloudBrainOne && ciTasks[i].Cloudbrain.JobType == "TRAIN") {
taskDetail.JobID = ciTasks[i].Cloudbrain.JobID
}
taskDetail.WaitTime = repo.GetCloudbrainWaitTime(ciTasks[i].Cloudbrain)

if ciTasks[i].Cloudbrain.DeletedAt != nilTime {
taskDetail.IsDelete = true
@@ -813,6 +781,17 @@ func GetCloudbrainsDetailData(ctx *context.Context) {
})
}

func getCloudbrainAiCenter(task models.Cloudbrain, ctx *context.Context) string {
if task.Type == models.TypeCloudBrainOne {
return ctx.Tr("repo.cloudbrain1")
} else if task.Type == models.TypeCloudBrainTwo {
return ctx.Tr("repo.cloudbrain2")
} else if task.Type == models.TypeC2Net {
return task.AiCenter
}
return ""
}

func GetCloudbrainsCreateHoursData(ctx *context.Context) {
recordCloudbrain, err := models.GetRecordBeginTime()
if err != nil {
@@ -1247,18 +1226,23 @@ func allCloudbrainHeader(ctx *context.Context) map[string]string {

return map[string]string{"A1": ctx.Tr("repo.cloudbrain_task"), "B1": ctx.Tr("repo.cloudbrain_type"), "C1": ctx.Tr("repo.modelarts.status"), "D1": ctx.Tr("repo.cloudbrain_task_type"),
"E1": ctx.Tr("repo.modelarts.createtime"), "F1": ctx.Tr("repo.modelarts.train_job.wait_time"), "G1": ctx.Tr("repo.modelarts.train_job.dura_time"),
"H1": ctx.Tr("repo.modelarts.train_job.start_time"),
"I1": ctx.Tr("repo.modelarts.train_job.end_time"), "J1": ctx.Tr("repo.modelarts.computing_resources"),
"K1": ctx.Tr("repo.cloudbrain_creator"), "L1": ctx.Tr("repo.repo_name"), "M1": ctx.Tr("repo.cloudbrain_task_name"), "N1": ctx.Tr("repo.modelarts.deletetime")}
"H1": ctx.Tr("cloudbrain.card_duration"),
"I1": ctx.Tr("repo.modelarts.train_job.start_time"), "J1": ctx.Tr("repo.modelarts.train_job.end_time"),
"K1": ctx.Tr("repo.modelarts.computing_resources"), "L1": ctx.Tr("cloudbrain.card_type"),
"M1": ctx.Tr("repo.grampus.train_job.ai_center"), "N1": ctx.Tr("cloudbrain.resource_specification"),
"O1": ctx.Tr("repo.cloudbrain_creator"), "P1": ctx.Tr("repo.repo_name"), "Q1": ctx.Tr("repo.cloudbrain_task_name"),
"R1": ctx.Tr("repo.modelarts.deletetime")}

}
func allCloudbrainValues(row int, rs *models.CloudbrainInfo, ctx *context.Context) map[string]string {
return map[string]string{getCellName("A", row): rs.DisplayJobName, getCellName("B", row): getCloudbrainType(rs, ctx), getCellName("C", row): rs.Status, getCellName("D", row): rs.JobType,
getCellName("E", row): time.Unix(int64(rs.Cloudbrain.CreatedUnix), 0).Format(CREATE_TIME_FORMAT), getCellName("F", row): getBrainWaitTime(rs),
getCellName("G", row): rs.TrainJobDuration, getCellName("H", row): getBrainStartTime(rs),
getCellName("I", row): getBrainEndTime(rs),
getCellName("J", row): rs.ComputeResource, getCellName("K", row): rs.Name, getCellName("L", row): getBrainRepo(rs),
getCellName("M", row): rs.JobName, getCellName("N", row): getBrainDeleteTime(rs),
getCellName("E", row): time.Unix(int64(rs.Cloudbrain.CreatedUnix), 0).Format(CREATE_TIME_FORMAT), getCellName("F", row): repo.GetCloudbrainWaitTime(rs.Cloudbrain),
getCellName("G", row): rs.TrainJobDuration, getCellName("H", row): repo.GetCloudbrainCardDuration(rs.Cloudbrain),
getCellName("I", row): getBrainStartTime(rs),
getCellName("J", row): getBrainEndTime(rs), getCellName("K", row): rs.ComputeResource, getCellName("L", row): getCloudbrainCardType(rs),
getCellName("M", row): repo.GetCloudbrainAiCenter(rs.Cloudbrain, ctx), getCellName("N", row): getCloudbrainFlavorName(rs),
getCellName("O", row): rs.Name, getCellName("P", row): getBrainRepo(rs),
getCellName("Q", row): rs.JobName, getCellName("R", row): getBrainDeleteTime(rs),
}
}
func getBrainRepo(rs *models.CloudbrainInfo) string {
@@ -1285,19 +1269,6 @@ func getBrainEndTime(rs *models.CloudbrainInfo) string {
}

}
func getBrainWaitTime(rs *models.CloudbrainInfo) string {
var waitTime int64
if rs.Cloudbrain.Status == string(models.JobWaiting) {
waitTime = time.Now().Unix() - rs.Cloudbrain.CreatedUnix.AsTime().Unix()
} else {
waitTime = int64(rs.Cloudbrain.StartTime - rs.Cloudbrain.CreatedUnix)
}
if waitTime <= 0 {
return "00:00:00"
} else {
return models.ConvertDurationToStr(waitTime)
}
}
func getCloudbrainType(rs *models.CloudbrainInfo, ctx *context.Context) string {
if rs.Cloudbrain.Type == models.TypeCloudBrainOne {
return ctx.Tr("repo.cloudbrain1")
@@ -1309,6 +1280,14 @@ func getCloudbrainType(rs *models.CloudbrainInfo, ctx *context.Context) string {
return ctx.Tr("repo.cloudbrain_untype")
}
}
func getCloudbrainCardType(rs *models.CloudbrainInfo) string {
_, cardType, _ := repo.GetCloudbrainCardNumAndType(rs.Cloudbrain)
return cardType
}
func getCloudbrainFlavorName(rs *models.CloudbrainInfo) string {
flavorName, _ := repo.GetCloudbrainFlavorName(rs.Cloudbrain)
return flavorName
}

func getBrainDeleteTime(rs *models.CloudbrainInfo) string {
nilTime := time.Time{}


+ 21
- 6
routers/api/v1/repo/modelarts.go View File

@@ -6,6 +6,7 @@
package repo

import (
"code.gitea.io/gitea/modules/notification"
"encoding/json"
"net/http"
"path"
@@ -42,8 +43,11 @@ func GetModelArtsNotebook(ctx *context.APIContext) {
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)
@@ -75,21 +79,26 @@ func GetModelArtsNotebook2(ctx *context.APIContext) {
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,
"ID": ID,
"JobName": job.JobName,
"JobStatus": result.Status,
"JobDuration": job.TrainJobDuration,
})

}
@@ -111,10 +120,13 @@ func GetModelArtsTrainJob(ctx *context.APIContext) {
ctx.NotFound(err)
return
}
oldStatus := job.Status
job.Status = modelarts.TransTrainJobStatus(result.IntStatus)
job.Duration = result.Duration
job.TrainJobDuration = result.TrainJobDuration
if oldStatus != job.Status {
notification.NotifyChangeCloudbrainStatus(job, oldStatus)
}
err = models.UpdateJob(job)
if err != nil {
log.Error("UpdateJob failed:", err)
@@ -155,7 +167,7 @@ func GetModelArtsTrainJobVersion(ctx *context.APIContext) {
log.Error("ConvertToJobResultPayload failed:", err)
return
}
oldStatus := job.Status
job.Status = result.JobStatus.State
if result.JobStatus.State != string(models.JobWaiting) && result.JobStatus.State != string(models.JobFailed) {
taskRoles := result.TaskRoles
@@ -168,6 +180,9 @@ func GetModelArtsTrainJobVersion(ctx *context.APIContext) {

if result.JobStatus.State != string(models.JobWaiting) {
models.ParseAndSetDurationFromCloudBrainOne(result, job)
if oldStatus != job.Status {
notification.NotifyChangeCloudbrainStatus(job, oldStatus)
}
err = models.UpdateJob(job)
if err != nil {
log.Error("UpdateJob failed:", err)


+ 8
- 8
routers/repo/ai_model_manage.go View File

@@ -152,6 +152,10 @@ func saveModelByParameters(jobId string, versionName string, name string, versio
}

func SaveNewNameModel(ctx *context.Context) {
if !ctx.Repo.CanWrite(models.UnitTypeModelManage) {
ctx.Error(403, ctx.Tr("repo.model_noright"))
return
}
name := ctx.Query("Name")
if name == "" {
ctx.Error(500, fmt.Sprintf("name or version is null."))
@@ -169,6 +173,10 @@ func SaveNewNameModel(ctx *context.Context) {
}

func SaveModel(ctx *context.Context) {
if !ctx.Repo.CanWrite(models.UnitTypeModelManage) {
ctx.Error(403, ctx.Tr("repo.model_noright"))
return
}
log.Info("save model start.")
JobId := ctx.Query("JobId")
VersionName := ctx.Query("VersionName")
@@ -177,16 +185,8 @@ func SaveModel(ctx *context.Context) {
label := ctx.Query("Label")
description := ctx.Query("Description")
engine := ctx.QueryInt("Engine")
trainTaskCreate := ctx.QueryBool("trainTaskCreate")
modelSelectedFile := ctx.Query("modelSelectedFile")
log.Info("engine=" + fmt.Sprint(engine) + " modelSelectedFile=" + modelSelectedFile)
if !trainTaskCreate {
if !ctx.Repo.CanWrite(models.UnitTypeModelManage) {
//ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
ctx.JSON(403, ctx.Tr("repo.model_noright"))
return
}
}

if JobId == "" || VersionName == "" {
ctx.Error(500, fmt.Sprintf("JobId or VersionName is null."))


+ 270
- 39
routers/repo/cloudbrain.go View File

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

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

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

"code.gitea.io/gitea/modules/timeutil"
@@ -222,6 +224,7 @@ func CloudBrainNew(ctx *context.Context) {
ctx.ServerError("get new cloudbrain info failed", err)
return
}
ctx.Data["PageIsGPUDebug"] = true
ctx.HTML(200, tplCloudBrainNew)
}

@@ -287,13 +290,17 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) {
return
}
}

datasetInfos, datasetNames, err := models.GetDatasetInfo(uuids)
if err != nil {
log.Error("GetDatasetInfo failed: %v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr(ctx.Tr("cloudbrain.error.dataset_select"), tpl, &form)
return
var datasetInfos map[string]models.DatasetInfo
var datasetNames string
//var
if uuids != "" {
datasetInfos, datasetNames, err = models.GetDatasetInfo(uuids)
if err != nil {
log.Error("GetDatasetInfo failed: %v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr(ctx.Tr("cloudbrain.error.dataset_select"), tpl, &form)
return
}
}

command := cloudbrain.GetCloudbrainDebugCommand()
@@ -302,6 +309,7 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) {
commandTrain, err := getTrainJobCommand(form)
if err != nil {
log.Error("getTrainJobCommand failed: %v", err)
cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr(err.Error(), tpl, &form)
return
}
@@ -370,7 +378,6 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) {
}
}


func CloudBrainInferenceJobCreate(ctx *context.Context, form auth.CreateCloudBrainInferencForm) {
ctx.Data["PageIsCloudBrain"] = true
displayJobName := form.DisplayJobName
@@ -391,6 +398,7 @@ func CloudBrainInferenceJobCreate(ctx *context.Context, form auth.CreateCloudBra
command, err := getInferenceJobCommand(form)
if err != nil {
log.Error("getTrainJobCommand failed: %v", err)
cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr(err.Error(), tpl, &form)
return
}
@@ -413,6 +421,7 @@ func CloudBrainInferenceJobCreate(ctx *context.Context, form auth.CreateCloudBra
}

if !jobNamePattern.MatchString(displayJobName) {
cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_jobname_err"), tpl, &form)
return
}
@@ -491,6 +500,7 @@ func CloudBrainInferenceJobCreate(ctx *context.Context, form auth.CreateCloudBra
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/inference-job")

}

/**
检查用户传输的参数是否符合专属资源池
*/
@@ -633,6 +643,7 @@ func CloudBrainTrainJobShow(ctx *context.Context) {
func cloudBrainShow(ctx *context.Context, tpName base.TplName, jobType models.JobType) {
ctx.Data["PageIsCloudBrain"] = true
debugListType := ctx.Query("debugListType")
cloudbrain.InitSpecialPool()

var task *models.Cloudbrain
var err error
@@ -644,22 +655,22 @@ func cloudBrainShow(ctx *context.Context, tpName base.TplName, jobType models.Jo

if err != nil {
log.Info("error:" + err.Error())
ctx.Data["error"] = err.Error()
ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
return
}

result, err := cloudbrain.GetJob(task.JobID)
if err != nil {
log.Info("error:" + err.Error())
ctx.Data["error"] = err.Error()
ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
return
}
hasSpec := false
if task.JobType == string(models.JobTypeTrain) {
if cloudbrain.TrainResourceSpecs == nil {
json.Unmarshal([]byte(setting.TrainResourceSpecs), &cloudbrain.TrainResourceSpecs)
}
hasSpec := false
for _, tmp := range cloudbrain.TrainResourceSpecs.ResourceSpec {
if tmp.Id == task.ResourceSpecId {
hasSpec = true
@@ -667,24 +678,7 @@ func cloudBrainShow(ctx *context.Context, tpName base.TplName, jobType models.Jo
ctx.Data["CpuNum"] = tmp.CpuNum
ctx.Data["MemMiB"] = tmp.MemMiB
ctx.Data["ShareMemMiB"] = tmp.ShareMemMiB
}
}

if !hasSpec && cloudbrain.SpecialPools != nil {
for _, specialPool := range cloudbrain.SpecialPools.Pools {

if specialPool.ResourceSpec != nil {

for _, spec := range specialPool.ResourceSpec {
if task.ResourceSpecId == spec.Id {
ctx.Data["GpuNum"] = spec.GpuNum
ctx.Data["CpuNum"] = spec.CpuNum
ctx.Data["MemMiB"] = spec.MemMiB
ctx.Data["ShareMemMiB"] = spec.ShareMemMiB
break
}
}
}
break
}
}

@@ -694,10 +688,12 @@ func cloudBrainShow(ctx *context.Context, tpName base.TplName, jobType models.Jo
}
for _, tmp := range cloudbrain.InferenceResourceSpecs.ResourceSpec {
if tmp.Id == task.ResourceSpecId {
hasSpec = true
ctx.Data["GpuNum"] = tmp.GpuNum
ctx.Data["CpuNum"] = tmp.CpuNum
ctx.Data["MemMiB"] = tmp.MemMiB
ctx.Data["ShareMemMiB"] = tmp.ShareMemMiB
break
}
}
} else {
@@ -706,10 +702,32 @@ func cloudBrainShow(ctx *context.Context, tpName base.TplName, jobType models.Jo
}
for _, tmp := range cloudbrain.ResourceSpecs.ResourceSpec {
if tmp.Id == task.ResourceSpecId {
hasSpec = true
ctx.Data["GpuNum"] = tmp.GpuNum
ctx.Data["CpuNum"] = tmp.CpuNum
ctx.Data["MemMiB"] = tmp.MemMiB
ctx.Data["ShareMemMiB"] = tmp.ShareMemMiB
break

}
}
}

if !hasSpec && cloudbrain.SpecialPools != nil {

for _, specialPool := range cloudbrain.SpecialPools.Pools {

if specialPool.ResourceSpec != nil {

for _, spec := range specialPool.ResourceSpec {
if task.ResourceSpecId == spec.Id {
ctx.Data["GpuNum"] = spec.GpuNum
ctx.Data["CpuNum"] = spec.CpuNum
ctx.Data["MemMiB"] = spec.MemMiB
ctx.Data["ShareMemMiB"] = spec.ShareMemMiB
break
}
}
}
}
}
@@ -728,14 +746,6 @@ func cloudBrainShow(ctx *context.Context, tpName base.TplName, jobType models.Jo
ctx.Data["resource_type"] = resourceType.Value
}
}
for _, specialPool := range cloudbrain.SpecialPools.Pools {

for _, resourceType := range specialPool.Pool {
if resourceType.Queue == jobRes.Config.GpuType {
ctx.Data["resource_type"] = resourceType.Value
}
}
}

} else if task.JobType == string(models.JobTypeInference) {
if inferenceGpuInfos == nil {
@@ -767,16 +777,30 @@ func cloudBrainShow(ctx *context.Context, tpName base.TplName, jobType models.Jo
}
}
}

if cloudbrain.SpecialPools != nil {
for _, specialPool := range cloudbrain.SpecialPools.Pools {
for _, resourceType := range specialPool.Pool {
if resourceType.Queue == jobRes.Config.GpuType {
ctx.Data["resource_type"] = resourceType.Value
}
}
}
}
taskRoles := jobRes.TaskRoles
taskRes, _ := models.ConvertToTaskPod(taskRoles[cloudbrain.SubTaskName].(map[string]interface{}))
ctx.Data["taskRes"] = taskRes
ctx.Data["ExitDiagnostics"] = taskRes.TaskStatuses[0].ExitDiagnostics
oldStatus := task.Status
task.Status = taskRes.TaskStatuses[0].State
task.ContainerID = taskRes.TaskStatuses[0].ContainerID
task.ContainerIp = taskRes.TaskStatuses[0].ContainerIP
models.ParseAndSetDurationFromCloudBrainOne(jobRes, task)

if task.DeletedAt.IsZero() { //normal record
if oldStatus != task.Status {
notification.NotifyChangeCloudbrainStatus(task, oldStatus)
}
err = models.UpdateJob(task)
if err != nil {
ctx.Data["error"] = err.Error()
@@ -892,6 +916,20 @@ func CloudBrainCommitImageShow(ctx *context.Context) {
ctx.HTML(200, tplCloudBrainImageSubmit)
}

func GetImage(ctx *context.Context) {

var ID = ctx.Params(":id")
id, _ := strconv.ParseInt(ID, 10, 64)

image, err := models.GetImageByID(id)
if err != nil {
log.Error("GetImageByID failed:%v", err.Error())
ctx.JSON(http.StatusNotFound, nil)
}
ctx.JSON(http.StatusOK, image)

}

func CloudBrainImageEdit(ctx *context.Context) {
ctx.Data["PageIsImageEdit"] = true
ctx.Data["PageFrom"] = ctx.Params(":from")
@@ -1116,12 +1154,15 @@ func CloudBrainStop(ctx *context.Context) {
errorMsg = "cloudbrain.Stopped_failed"
break
}
oldStatus := task.Status
task.Status = string(models.JobStopped)
if task.EndTime == 0 {
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, ctx.Data["msgID"])
@@ -1215,11 +1256,15 @@ func logErrorAndUpdateJobStatus(err error, taskInfo *models.Cloudbrain) {
if err != nil {
log.Warn("Failed to stop cloudBrain job:"+taskInfo.JobID, err)
} else {
oldStatus := taskInfo.Status
taskInfo.Status = string(models.JobStopped)
if taskInfo.EndTime == 0 {
taskInfo.EndTime = timeutil.TimeStampNow()
}
taskInfo.ComputeAndSetDuration()
if oldStatus != taskInfo.Status {
notification.NotifyChangeCloudbrainStatus(taskInfo, oldStatus)
}
err = models.UpdateJob(taskInfo)
if err != nil {
log.Warn("UpdateJob failed", err)
@@ -1699,9 +1744,13 @@ func SyncCloudbrainStatus() {
jobRes, _ := models.ConvertToJobResultPayload(result.Payload)
taskRoles := jobRes.TaskRoles
taskRes, _ := models.ConvertToTaskPod(taskRoles[cloudbrain.SubTaskName].(map[string]interface{}))
oldStatus := task.Status
task.Status = taskRes.TaskStatuses[0].State
if task.Status != string(models.JobWaiting) {
models.ParseAndSetDurationFromCloudBrainOne(jobRes, task)
if oldStatus != task.Status {
notification.NotifyChangeCloudbrainStatus(task, oldStatus)
}
err = models.UpdateJob(task)
if err != nil {
log.Error("UpdateJob(%s) failed:%v", task.JobName, err)
@@ -1728,6 +1777,9 @@ func SyncCloudbrainStatus() {
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.DisplayJobName, err)
@@ -1746,6 +1798,7 @@ func SyncCloudbrainStatus() {
}

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)
@@ -1755,6 +1808,9 @@ func SyncCloudbrainStatus() {
}
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)
@@ -1769,6 +1825,7 @@ func SyncCloudbrainStatus() {
}

if result != nil {
oldStatus := task.Status
task.Status = modelarts.TransTrainJobStatus(result.IntStatus)
task.Duration = result.Duration / 1000
task.TrainJobDuration = result.TrainJobDuration
@@ -1781,6 +1838,9 @@ func SyncCloudbrainStatus() {
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)
@@ -1801,6 +1861,7 @@ func SyncCloudbrainStatus() {
if len(result.JobInfo.Tasks[0].CenterID) == 1 && len(result.JobInfo.Tasks[0].CenterName) == 1 {
task.AiCenter = result.JobInfo.Tasks[0].CenterID[0] + "+" + result.JobInfo.Tasks[0].CenterName[0]
}
oldStatus := task.Status
task.Status = grampus.TransTrainJobStatus(result.JobInfo.Status)
task.Duration = result.JobInfo.RunSec
task.TrainJobDuration = models.ConvertDurationToStr(task.Duration)
@@ -1812,6 +1873,9 @@ func SyncCloudbrainStatus() {
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)
@@ -2662,3 +2726,170 @@ func GetBenchmarkTypes(ctx *context.Context) *models.BenchmarkTypes {
}
return benchmarkTypesMap[lang]
}

func GetCloudbrainAiCenter(task models.Cloudbrain, ctx *context.Context) string {
if task.Type == models.TypeCloudBrainOne {
return ctx.Tr("repo.cloudbrain1")
} else if task.Type == models.TypeCloudBrainTwo {
return ctx.Tr("repo.cloudbrain2")
} else if task.Type == models.TypeC2Net {
return getCutStringAiCenterByAiCenter(task.AiCenter)
}
return ""
}
func getCutStringAiCenterByAiCenter(aiCenter string) string {
if aiCenter == "" {
return ""
}
index := strings.LastIndex(aiCenter, "+")
return aiCenter[index+1:]

}
func GetCloudbrainCluster(task models.Cloudbrain, ctx *context.Context) string {
if task.Type == models.TypeCloudBrainOne || task.Type == models.TypeCloudBrainTwo {
return ctx.Tr("cloudbrain.resource_cluster_openi")
} else if task.Type == models.TypeC2Net {
return ctx.Tr("cloudbrain.resource_cluster_c2net")
}
return ""
}
func GetCloudbrainCardDuration(task models.Cloudbrain) string {
cardNum, _, _ := GetCloudbrainCardNumAndType(task)
cardDuration := models.ConvertDurationToStr(int64(cardNum) * task.Duration)
return cardDuration
}
func GetCloudbrainWaitTime(task models.Cloudbrain) string {
var waitTime string
if task.Status == string(models.JobWaiting) {
waitTimeInt := time.Now().Unix() - task.CreatedUnix.AsTime().Unix()
waitTime = models.ConvertDurationToStr(waitTimeInt)
if waitTimeInt < 0 {
waitTime = "00:00:00"
}
} else if task.Status == string(models.JobStopped) && task.StartTime.AsTime().Unix() == 0 {
waitTimeInt := task.EndTime.AsTime().Unix() - task.CreatedUnix.AsTime().Unix()
waitTime = models.ConvertDurationToStr(waitTimeInt)
if waitTimeInt < 0 {
waitTime = "00:00:00"

}
} else {
waitTimeInt := task.StartTime.AsTime().Unix() - task.CreatedUnix.AsTime().Unix()
waitTime = models.ConvertDurationToStr(waitTimeInt)
if waitTimeInt < 0 {
waitTime = "00:00:00"
}
}
return waitTime
}

func GetCloudbrainCardNumAndType(task models.Cloudbrain) (int, string, error) {
if !models.SpecsMapInitFlag {
models.InitCloudbrainOneResourceSpecMap()
}
if !models.GpuInfosMapInitFlag {
models.InitCloudbrainOneGpuInfoMap()
}
flavorName, err := GetCloudbrainFlavorName(task)
if err != nil {
return 0, "", nil
}
return getCardNumAndTypeByFlavorname(flavorName)
}

func getCardNumAndTypeByFlavorname(FlavorName string) (int, string, error) {
if FlavorName == "" {
return 0, "", nil
} else {
var beginIndex = strings.Index(FlavorName, ":")
var lastIndex = strings.LastIndex(FlavorName, ":")
var endIndex = strings.Index(FlavorName, "*")
if endIndex >= (beginIndex+1) && lastIndex >= (endIndex+1) {
cardNum, err := strconv.Atoi(strings.TrimSpace(FlavorName[beginIndex+1 : endIndex]))
if err != nil {
log.Error("strconv.Atoi failed: %v", err)
return 0, "", err
}
cardType := strings.TrimSpace(FlavorName[endIndex+1 : lastIndex])
return cardNum, cardType, err
}
return 0, "", nil
}
}

func GetCloudbrainFlavorName(task models.Cloudbrain) (string, error) {
if task.Type == models.TypeCloudBrainOne {
resourceSpec, gpuInfo, err := getCloudBrainOneResourceSpec(task)
if err != nil {
log.Info("getCloudBrainOneResourceSpec err:", err)
return "", err
} else {
if resourceSpec == nil || gpuInfo == nil {
err := errors.New("resourceSpec or gpuInfo is nil")
return "", err
} else {
CloudbrainOneFlavorName := "GPU:" + strconv.Itoa(resourceSpec.GpuNum) + "*Nvidia-" + gpuInfo.Value +
" | CPU:" + strconv.Itoa(resourceSpec.CpuNum) + "核" + strconv.Itoa(resourceSpec.MemMiB) + "MB"
return CloudbrainOneFlavorName, nil
}
}
} else if (task.Type == models.TypeCloudBrainTwo || task.Type == models.TypeC2Net) && task.FlavorName != "" {
replaceFlavorName := strings.ReplaceAll(task.FlavorName, ":", ":")
return replaceFlavorName, nil
} else if task.Type == models.TypeCloudBrainTwo && task.FlavorName == "" && task.FlavorCode != "" {
cloudbrainTwoFlavorName := getFlavorNameByFlavorCode(task.FlavorCode)
return cloudbrainTwoFlavorName, nil
} else if task.Type == models.TypeCloudBrainTwo && task.JobType == string(models.JobTypeDebug) && task.FlavorName == "" && task.FlavorCode == "" {
tasks, err := models.GetModelartsReDebugTaskByJobId(task.JobID)
if err != nil {
return "", err
}
if len(tasks) >= 1 {
return getFlavorNameByFlavorCode(tasks[0].FlavorCode), nil
}
return "", nil
}
return "", nil
}

func getCloudBrainOneResourceSpec(task models.Cloudbrain) (*models.ResourceSpec, *models.GpuInfo, error) {
gpuQueueDefault := "openidebug"
if task.GpuQueue != "" {
gpuQueueDefault = task.GpuQueue
}
if task.ResourceSpecId >= 0 {
if task.JobType == string(models.JobTypeTrain) {
if models.CloudbrainTrainResourceSpecsMap[task.ResourceSpecId] != nil {
return models.CloudbrainTrainResourceSpecsMap[task.ResourceSpecId], models.CloudbrainTrainGpuInfosMap[gpuQueueDefault], nil
} else {
return models.CloudbrainSpecialResourceSpecsMap[task.ResourceSpecId], models.CloudbrainSpecialGpuInfosMap[gpuQueueDefault], nil
}
} else if task.JobType == string(models.JobTypeDebug) {
if models.CloudbrainDebugResourceSpecsMap[task.ResourceSpecId] != nil {
return models.CloudbrainDebugResourceSpecsMap[task.ResourceSpecId], models.CloudbrainDebugGpuInfosMap[gpuQueueDefault], nil
} else {
return models.CloudbrainSpecialResourceSpecsMap[task.ResourceSpecId], models.CloudbrainSpecialGpuInfosMap[gpuQueueDefault], nil
}
} else if task.JobType == string(models.JobTypeInference) {
return models.CloudbrainInferenceResourceSpecsMap[task.ResourceSpecId], models.CloudbrainInferenceGpuInfosMap[gpuQueueDefault], nil
} else if task.JobType == string(models.JobTypeBenchmark) || task.JobType == string(models.JobTypeSnn4imagenet) || task.JobType == string(models.JobTypeBrainScore) {
return models.CloudbrainBenchmarkResourceSpecsMap[task.ResourceSpecId], models.CloudbrainBenchmarkGpuInfosMap[gpuQueueDefault], nil
}
} else {
err := errors.New("ResourceSpecId is null")
return nil, nil, err
}
return nil, nil, nil
}
func getFlavorNameByFlavorCode(flavorCode string) string {
index := strings.LastIndex(flavorCode, ".")
cardNum, err := strconv.Atoi(strings.TrimSpace(flavorCode[index+1 : len(flavorCode)]))
if err != nil {
log.Error("strconv.Atoi failed: %v", err)
return ""
}
cloudbrainTwoFlavorName := "Ascend:" + strings.TrimSpace(flavorCode[index+1:len(flavorCode)]) +
"*Ascend-910(" + strconv.Itoa(cardNum*32) + "GB)|ARM:" + strconv.Itoa(cardNum*24) +
"核" + strconv.Itoa(cardNum*256) + "GB"
return cloudbrainTwoFlavorName
}

+ 22
- 13
routers/repo/grampus.go View File

@@ -1,15 +1,8 @@
package repo

import (
"code.gitea.io/gitea/modules/auth"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/grampus"
"code.gitea.io/gitea/modules/modelarts"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
"encoding/json"
"errors"
"github.com/unknwon/com"
"io/ioutil"
"net/http"
"os"
@@ -18,6 +11,15 @@ import (
"strings"
"time"

"code.gitea.io/gitea/modules/auth"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/grampus"
"code.gitea.io/gitea/modules/modelarts"
"code.gitea.io/gitea/modules/notification"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
"github.com/unknwon/com"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/cloudbrain"
@@ -64,7 +66,7 @@ func grampusTrainJobNewDataPrepare(ctx *context.Context, processType string) err
ctx.Data["PageIsCloudBrain"] = true

t := time.Now()
var displayJobName = cutString(ctx.User.Name, 5) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:]
var displayJobName = jobNamePrefixValid(cutString(ctx.User.Name, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:]
ctx.Data["display_job_name"] = displayJobName

//get valid images
@@ -469,7 +471,7 @@ func GrampusTrainJobNpuCreate(ctx *context.Context, form auth.CreateGrampusTrain
//todo: upload code (send to file_server todo this work?)
if err := obsMkdir(setting.CodePathPrefix + jobName + modelarts.OutputPath); err != nil {
log.Error("Failed to obsMkdir_output: %s (%v)", repo.FullName(), err)
grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU)
grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU)
ctx.RenderWithErr("Failed to obsMkdir_output", tplGrampusTrainJobNPUNew, &form)
return
}
@@ -550,12 +552,15 @@ func GrampusStopJob(ctx *context.Context) {
errorMsg = res.ErrorMsg
break
}
oldStatus := task.Status
task.Status = string(models.GrampusStatusStopped)
if task.EndTime == 0 {
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, ctx.Data["msgID"])
@@ -626,7 +631,7 @@ func GrampusTrainJobShow(ctx *context.Context) {
task, err := models.GetCloudbrainByJobIDWithDeleted(ctx.Params(":jobid"))
if err != nil {
log.Error("GetCloudbrainByJobID failed:" + err.Error())
ctx.ServerError("system error", err)
ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
return
}

@@ -634,14 +639,15 @@ func GrampusTrainJobShow(ctx *context.Context) {
result, err := grampus.GetJob(task.JobID)
if err != nil {
log.Error("GetJob failed:" + err.Error())
//ctx.ServerError("GetJob failed", err)
//return
ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
return
}

if result != nil {
if len(result.JobInfo.Tasks[0].CenterID) == 1 && len(result.JobInfo.Tasks[0].CenterName) == 1 {
task.AiCenter = result.JobInfo.Tasks[0].CenterID[0] + "+" + result.JobInfo.Tasks[0].CenterName[0]
}
oldStatus := task.Status
task.Status = grampus.TransTrainJobStatus(result.JobInfo.Status)
if task.Status != result.JobInfo.Status || result.JobInfo.Status == models.GrampusStatusRunning {
task.Duration = result.JobInfo.RunSec
@@ -654,6 +660,9 @@ func GrampusTrainJobShow(ctx *context.Context) {
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 failed:" + err.Error())


+ 40
- 13
routers/repo/modelarts.go View File

@@ -265,33 +265,38 @@ func NotebookShow(ctx *context.Context) {
var ID = ctx.Params(":id")
task, err := models.GetCloudbrainByIDWithDeleted(ID)
if err != nil {
ctx.Data["error"] = err.Error()
ctx.RenderWithErr(err.Error(), tplModelArtsNotebookShow, nil)
log.Error("GET job error", err.Error())
ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
return
}

result, err := modelarts.GetNotebook2(task.JobID)
if err != nil {
ctx.Data["error"] = err.Error()
ctx.RenderWithErr(err.Error(), tplModelArtsNotebookShow, 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 {
ctx.Data["error"] = err.Error()
ctx.RenderWithErr(err.Error(), tplModelArtsNotebookShow, 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
}
}

datasetDownload := make([]models.DatasetDownload, 0)
@@ -526,6 +531,8 @@ func NotebookManage(ctx *context.Context) {
Description: task.Description,
CreatedUnix: createTime,
UpdatedUnix: createTime,
FlavorCode: task.FlavorCode,
FlavorName: task.FlavorName,
}

err = models.RestartCloudbrain(task, newTask)
@@ -538,11 +545,15 @@ func NotebookManage(ctx *context.Context) {
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"])
@@ -567,7 +578,7 @@ func NotebookDel(ctx *context.Context) {
var listType = ctx.Query("debugListType")
task := ctx.Cloudbrain

if task.Status != string(models.ModelArtsCreateFailed) && task.Status != string(models.ModelArtsStartFailed) && task.Status != string(models.ModelArtsStopped) {
if task.Status != string(models.ModelArtsCreateFailed) && task.Status != string(models.ModelArtsStartFailed) && task.Status != string(models.ModelArtsStopped) && task.Status != string(models.ModelArtsDeleted) {
log.Error("the job(%s) has not been stopped", task.JobName)
ctx.RenderWithErr("the job has not been stopped", tplDebugJobIndex, nil)
return
@@ -680,7 +691,7 @@ func trainJobNewDataPrepare(ctx *context.Context) error {
//}

t := time.Now()
var displayJobName = cutString(ctx.User.Name, 5) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:]
var displayJobName = jobNamePrefixValid(cutString(ctx.User.Name, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:]
ctx.Data["display_job_name"] = displayJobName

attachs, err := models.GetModelArtsTrainAttachments(ctx.User.ID)
@@ -785,7 +796,7 @@ func trainJobErrorNewDataPrepare(ctx *context.Context, form auth.CreateModelArts
//}

t := time.Now()
var displayJobName = cutString(ctx.User.Name, 5) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:]
var displayJobName = jobNamePrefixValid(cutString(ctx.User.Name, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:]
ctx.Data["display_job_name"] = displayJobName

attachs, err := models.GetModelArtsTrainAttachments(ctx.User.ID)
@@ -838,6 +849,12 @@ func trainJobErrorNewDataPrepare(ctx *context.Context, form auth.CreateModelArts
ctx.Data["config_list"] = configList.ParaConfigs
ctx.Data["bootFile"] = form.BootFile
ctx.Data["uuid"] = form.Attachment
_, datasetNames, err := models.GetDatasetInfo(form.Attachment)
if err != nil {
log.Error("GetDatasetInfo failed: %v", err, ctx.Data["MsgID"])
return nil
}
ctx.Data["dataset_name"] = datasetNames
ctx.Data["branch_name"] = form.BranchName
ctx.Data["datasetType"] = models.TypeCloudBrainTwo

@@ -962,7 +979,7 @@ func versionErrorDataPrepare(ctx *context.Context, form auth.CreateModelArtsTrai
}

t := time.Now()
var jobName = cutString(ctx.User.Name, 5) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:]
var jobName = jobNamePrefixValid(cutString(ctx.User.Name, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:]
ctx.Data["job_name"] = task.JobName

attachs, err := models.GetModelArtsTrainAttachments(ctx.User.ID)
@@ -1727,7 +1744,11 @@ func TrainJobShow(ctx *context.Context) {

if err != nil {
log.Error("GetVersionListTasks(%s) failed:%v", jobID, err.Error())
ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobShow, nil)
ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
return
}
if len(VersionListTasks) == 0 {
ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
return
}
//设置权限
@@ -2305,7 +2326,7 @@ func inferenceJobNewDataPrepare(ctx *context.Context) error {
ctx.Data["newInference"] = true

t := time.Now()
var displayJobName = cutString(ctx.User.Name, 5) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:]
var displayJobName = jobNamePrefixValid(cutString(ctx.User.Name, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:]
ctx.Data["display_job_name"] = displayJobName

attachs, err := models.GetModelArtsTrainAttachments(ctx.User.ID)
@@ -2429,6 +2450,12 @@ func inferenceJobErrorNewDataPrepare(ctx *context.Context, form auth.CreateModel
ctx.Data["config_list"] = configList.ParaConfigs
ctx.Data["bootFile"] = form.BootFile
ctx.Data["uuid"] = form.Attachment
_, datasetNames, err := models.GetDatasetInfo(form.Attachment)
if err != nil {
log.Error("GetDatasetInfo failed: %v", err, ctx.Data["MsgID"])
return nil
}
ctx.Data["dataset_name"] = datasetNames
ctx.Data["branch_name"] = form.BranchName
ctx.Data["model_name"] = form.ModelName
ctx.Data["model_version"] = form.ModelVersion
@@ -2450,7 +2477,7 @@ func InferenceJobShow(ctx *context.Context) {

if err != nil {
log.Error("GetInferenceTask(%s) failed:%v", jobID, err.Error())
ctx.RenderWithErr(err.Error(), tplModelArtsInferenceJobShow, nil)
ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
return
}
//设置权限


+ 76
- 8
routers/repo/user_data_analysis.go View File

@@ -5,6 +5,8 @@ import (
"net/http"
"net/url"
"os"
"strconv"
"strings"
"time"

"code.gitea.io/gitea/models"
@@ -404,7 +406,7 @@ func queryMetrics(ctx *context.Context, tableName string, startTime time.Time, e
if tableName == "public.user_business_analysis_yesterday" {
mapInterface["datarecordbegintime"] = setting.RadarMap.GrowthBeginTime
if len(result) > 0 {
dateTime := time.Unix(result[0].CountDate, 0)
dateTime := time.Unix(result[0].CountDate, 0).AddDate(0, 0, 1)
mapInterface["lastUpdatedTime"] = dateTime.Format("2006-01-02 15:04:05")
} else {
mapInterface["lastUpdatedTime"] = ""
@@ -450,7 +452,7 @@ func DownloadUserDefineFile(ctx *context.Context) {
func QueryUserMetricsCurrentMonth(ctx *context.Context) {

currentTimeNow := time.Now()
pageEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 23, 59, 59, 0, currentTimeNow.Location())
pageEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 0, 0, 0, 0, currentTimeNow.Location())
pageStartTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), 1, 0, 0, 0, 0, currentTimeNow.Location())
pageStartTime = getStartTime(pageStartTime)
queryMetrics(ctx, "public.user_business_analysis_current_month", pageStartTime, pageEndTime)
@@ -476,7 +478,7 @@ func QueryUserMetricsCurrentWeek(ctx *context.Context) {
}
pageStartTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 0, 0, 0, 0, time.Local).AddDate(0, 0, offset)
pageStartTime = getStartTime(pageStartTime)
pageEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 23, 59, 59, 0, currentTimeNow.Location())
pageEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 0, 0, 0, 0, currentTimeNow.Location())
queryMetrics(ctx, "public.user_business_analysis_current_week", pageStartTime, pageEndTime)
}
func QueryUserStaticCurrentWeek(ctx *context.Context) {
@@ -490,7 +492,7 @@ func QueryUserMetricsCurrentYear(ctx *context.Context) {
currentTimeNow := time.Now()
pageStartTime := time.Date(currentTimeNow.Year(), 1, 1, 0, 0, 0, 0, currentTimeNow.Location())
pageStartTime = getStartTime(pageStartTime)
pageEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 23, 59, 59, 0, currentTimeNow.Location())
pageEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 0, 0, 0, 0, currentTimeNow.Location())
queryMetrics(ctx, "public.user_business_analysis_current_year", pageStartTime, pageEndTime)
}
func QueryUserStaticCurrentYear(ctx *context.Context) {
@@ -500,7 +502,7 @@ func QueryUserMetricsLast30Day(ctx *context.Context) {
currentTimeNow := time.Now()
pageStartTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 0, 0, 0, 0, time.Local).AddDate(0, 0, -30)
pageStartTime = getStartTime(pageStartTime)
pageEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 23, 59, 59, 0, currentTimeNow.Location())
pageEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 0, 0, 0, 0, currentTimeNow.Location())
queryMetrics(ctx, "public.user_business_analysis_last30_day", pageStartTime, pageEndTime)
}
func QueryUserStaticLast30Day(ctx *context.Context) {
@@ -518,7 +520,7 @@ func QueryUserStaticLastMonth(ctx *context.Context) {
queryUserDataPage(ctx, "public.user_business_analysis_last_month", new(models.UserBusinessAnalysisLastMonth))
}
func QueryUserMetricsYesterday(ctx *context.Context) {
currentTimeNow := time.Now()
currentTimeNow := time.Now().AddDate(0, 0, -1)
pageStartTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 0, 0, 0, 0, time.Local)
pageStartTime = getStartTime(pageStartTime)
pageEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 23, 59, 59, 0, currentTimeNow.Location())
@@ -531,7 +533,7 @@ func QueryUserMetricsAll(ctx *context.Context) {
currentTimeNow := time.Now()
pageStartTime := time.Date(2022, 4, 5, 0, 0, 0, 0, currentTimeNow.Location())
pageStartTime = getStartTime(pageStartTime)
pageEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 23, 59, 59, 0, currentTimeNow.Location())
pageEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 0, 0, 0, 0, currentTimeNow.Location())
queryMetrics(ctx, "public.user_business_analysis_all", pageStartTime, pageEndTime)
}
func QueryUserStaticAll(ctx *context.Context) {
@@ -611,7 +613,15 @@ func QueryUserStaticDataPage(ctx *context.Context) {
ctx.JSON(http.StatusOK, ctx.Tr("user.static.downloadinfo")+"/api/v1/download_user_define_file?filename="+filename)
} else {
mapInterface := make(map[string]interface{})
re, count := models.QueryUserStaticDataPage(pageOpts)
key := startTime.Format("2006-01-02") + endTime.Format("2006-01-02")
log.Info("db key =" + key)
re, count := models.QueryDataForUserDefineFromDb(pageOpts, key)
if count == 0 {
wikiMap, _ := queryWikiCountMap(startTime, endTime)
re, count = models.QueryUserStaticDataForUserDefine(pageOpts, wikiMap)
models.WriteDataToDb(re, key)
}
re, count = models.QueryDataForUserDefineFromDb(pageOpts, key)
mapInterface["data"] = re
mapInterface["count"] = count
ctx.JSON(http.StatusOK, mapInterface)
@@ -839,3 +849,61 @@ func writeUserActivityToExcel(startTime time.Time, endTime time.Time, filePath s
log.Info("write to file succeed, filepath=" + filePath)
}
}

// URL: /api/v1/query_user_login?userId=1,2,3,4
func QueryUserLoginInfo(ctx *context.Context) {
userId := ctx.Query("userId")
userIds := strings.Split(userId, ",")
userIdInt := make([]int64, 0)
for _, id := range userIds {
idInt, err := strconv.ParseInt(id, 10, 64)
if err == nil {
userIdInt = append(userIdInt, idInt)
}
}
result := models.QueryUserLoginInfo(userIdInt)

xlsx := excelize.NewFile()
sheetName := ctx.Tr("用户登录信息")
index := xlsx.NewSheet(sheetName)
xlsx.DeleteSheet("Sheet1")

excelHeader := make([]string, 0)
excelHeader = append(excelHeader, "用户ID")
excelHeader = append(excelHeader, "登录IP")
excelHeader = append(excelHeader, "登录时间")

excelHeaderMap := make(map[string]string, 0)
var j byte
j = 0
for _, value := range excelHeader {
excelColumn := getColumn(j) + fmt.Sprint(1)
log.Info("excelColumn=" + excelColumn)
excelHeaderMap[excelColumn] = value
j++
}
for k, v := range excelHeaderMap {
//设置单元格的值
xlsx.SetCellValue(sheetName, k, v)
}
for i, userLogin := range result {
row := i + 2
rows := fmt.Sprint(row)
var tmp byte
tmp = 0
xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userLogin.UId)
tmp = tmp + 1
xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userLogin.IpAddr)
tmp = tmp + 1
formatTime := userLogin.CreatedUnix.Format("2006-01-02 15:04:05")
xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, formatTime)
}
//设置默认打开的表单
xlsx.SetActiveSheet(index)
filename := sheetName + "_" + time.Now().Format("2006-01-02 15:04:05") + ".xlsx"
ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+url.QueryEscape(filename))
ctx.Resp.Header().Set("Content-Type", "application/octet-stream")
if _, err := xlsx.WriteTo(ctx.Resp); err != nil {
log.Info("writer exel error." + err.Error())
}
}

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

@@ -484,6 +484,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
)
} else if isNoteBook {
ctx.Data["FileContent"] = string(buf)
ctx.Data["FileParentURL"] = path.Dir(rawLink+"/"+ctx.Repo.TreePath) + "/"
} else {
// Building code view blocks with line number on server side.
var fileContent string


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

@@ -1016,6 +1016,7 @@ func RegisterRoutes(m *macaron.Macaron) {
}, context.RepoAssignment(), context.RepoMustNotBeArchived(), reqRepoAdmin)

m.Group("/image/:id", func() {
m.Get("", repo.GetImage)
m.Get("/:from", cloudbrain.AdminOrImageCreaterRight, repo.CloudBrainImageEdit)
m.Post("", cloudbrain.AdminOrImageCreaterRight, bindIgnErr(auth.EditImageCloudBrainForm{}), repo.CloudBrainImageEditPost)
m.Delete("", cloudbrain.AdminOrImageCreaterRight, repo.CloudBrainImageDelete)
@@ -1135,7 +1136,7 @@ func RegisterRoutes(m *macaron.Macaron) {
})
}, context.RepoRef())
m.Group("/modelmanage", func() {
m.Post("/create_model", reqRepoModelManageWriter, repo.SaveModel)
m.Post("/create_model", repo.SaveModel)
m.Post("/create_model_convert", reqRepoModelManageWriter, repo.SaveModelConvert)
m.Post("/create_new_model", repo.SaveNewNameModel)
m.Delete("/delete_model", repo.DeleteModel)


+ 26
- 2
routers/search.go View File

@@ -313,9 +313,8 @@ func searchRepo(ctx *context.Context, TableName string, Key string, Page int, Pa

res, err := client.Search(TableName).Query(boolQ).SortBy(getSort(SortBy, ascending, "num_stars", false)...).From(from).Size(Size).Highlight(queryHighlight("alias", "description", "topics")).Do(ctx.Req.Context())
if err == nil {
searchJson, _ := json.Marshal(res)
log.Info("searchJson=" + string(searchJson))
esresult := makeRepoResult(res, Key, OnlyReturnNum, language)
setForkRepoOrder(esresult)
resultObj.Total = resultObj.PrivateTotal + esresult.Total
isNeedSort := false
if len(resultObj.Result) > 0 {
@@ -348,6 +347,30 @@ func searchRepo(ctx *context.Context, TableName string, Key string, Page int, Pa
}
}

func setForkRepoOrder(esresult *SearchRes) {
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
}
}
}
}
}

func sortRepo(Result []map[string]interface{}, SortBy string, ascending bool) {
orderBy := ""
switch SortBy {
@@ -479,6 +502,7 @@ func makeRepoResult(sRes *elastic.SearchResult, Key string, OnlyReturnNum bool,
record["num_stars"] = recordSource["num_stars"]
record["num_forks"] = recordSource["num_forks"]
record["lower_alias"] = recordSource["lower_alias"]
record["fork_id"] = recordSource["fork_id"]
if recordSource["topics"] != nil {
topicsStr := recordSource["topics"].(string)
log.Info("topicsStr=" + topicsStr)


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

@@ -23,6 +23,7 @@ import (
"code.gitea.io/gitea/modules/modelarts"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/routers/repo"
issue_service "code.gitea.io/gitea/services/issue"
pull_service "code.gitea.io/gitea/services/pull"

@@ -834,6 +835,11 @@ func Cloudbrains(ctx *context.Context) {
ciTasks[i].CanDebug = true
ciTasks[i].CanDel = true
ciTasks[i].Cloudbrain.ComputeResource = task.ComputeResource
ciTasks[i].Cloudbrain.AiCenter = repo.GetCloudbrainAiCenter(task.Cloudbrain, ctx)
_, cardType, _ := repo.GetCloudbrainCardNumAndType(task.Cloudbrain)
ciTasks[i].Cloudbrain.CardType = cardType
ciTasks[i].Cloudbrain.Cluster = repo.GetCloudbrainCluster(task.Cloudbrain, ctx)

}

pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, getTotalPage(count, setting.UI.IssuePagingNum))


+ 3
- 3
routers/user/profile.go View File

@@ -116,8 +116,8 @@ func Profile(ctx *context.Context) {
}

var opts = models.FindOrgMembersOpts{
OrgID: org.ID,
PublicOnly: true,
OrgID: org.ID,
PublicOnly: true,
}

if ctx.User != nil {
@@ -261,7 +261,7 @@ func Profile(ctx *context.Context) {
IsOwner: isOwner,
ListOptions: models.ListOptions{
Page: page,
PageSize: setting.UI.ExplorePagingNum,
PageSize: setting.UI.User.RepoPagingNum,
},
CloudBrainType: -1,
}


+ 111
- 48
templates/admin/cloudbrain/list.tmpl View File

@@ -18,7 +18,7 @@
data-all-compute="{{.i18n.Tr "admin.cloudbrain.all_computing_resources"}}"
data-all-status="{{.i18n.Tr "admin.cloudbrain.all_status"}}"></div>
{{template "admin/navbar" .}}
<div class="ui container" style="width: 80%;">
<div class="ui container" style="width: 95%;">
{{template "base/alert" .}}
<div class="ui grid">
<div class="row" style="border: 1px solid #d4d4d5;margin-top: 15px;padding-top: 0;">
@@ -34,34 +34,46 @@
<!-- 表头 -->
<div class="ui grid stackable" style="background: #f0f0f0;;">
<div class="row">
<div class="two wide column nowrap">
<span style="margin:0 6px">{{$.i18n.Tr "repo.cloudbrain_task"}}</span>
<div class="two wide column nowrap" style="width:10% !important;">
<span>{{$.i18n.Tr "repo.cloudbrain_task"}}</span>
</div>
<div class="one wide column text center nowrap">
<span style="margin:0 6px">{{$.i18n.Tr "repo.cloudbrain_task_type"}}</span>
<!-- 集群 -->
<div class="one wide column text center nowrap" style="width:6% !important;">
<span>{{$.i18n.Tr "repo.modelarts.cluster"}}</span>
</div>
<div class="two wide column text center nowrap" style="width: 10% !important;">
<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="two wide column text center nowrap" style="width: 10% !important;">
<div class="two wide column text center nowrap" style="width: 8% !important;">
<span>{{$.i18n.Tr "repo.modelarts.createtime"}}</span>
</div>
<div class="one wide column text center nowrap">
<div class="one wide column text center nowrap" style="width: 5% !important;">
<span>{{$.i18n.Tr "repo.cloudbrain_status_runtime"}}</span>
</div>
<div class="one wide column text center nowrap">
<div class="one wide column text center nowrap" style="width: 5% !important;">
<span>{{$.i18n.Tr "repo.modelarts.computing_resources"}}</span>
</div>
<div class="one wide column text center nowrap">
<!-- 智算中心 -->
<div class="one wide column text center nowrap" style="width:8% !important;">
<span>{{$.i18n.Tr "repo.modelarts.ai_center"}}</span>
</div>
<!-- XPU类型 -->
<div class="one wide column text center nowrap" style="width:8% !important;">
<span>{{$.i18n.Tr "repo.modelarts.card_type"}}</span>
</div>
<div class="one wide column text center nowrap" style="width:4% !important;">
<span>{{$.i18n.Tr "repo.cloudbrain_creator"}}</span>
</div>
<div class="two wide column text center nowrap">
<div class="two wide column text center nowrap" style="width:10% !important;">
<span>{{$.i18n.Tr "repository"}}</span>
</div>
<div class="two wide column text center nowrap">
<div class="two wide column text center nowrap" style="width:10% !important;">
<span>{{.i18n.Tr "admin.cloudbrain.cloudbrain_name"}}</span>
</div>
<div class="two wide column text center nowrap" style="width: 17.5%!important;">
<div class="two wide column text center nowrap" style="width: 12%!important;">
<span>{{$.i18n.Tr "repo.cloudbrain_operate"}}</span>
</div>
</div>
@@ -78,24 +90,24 @@
{{$JobID = .JobID}}
{{end}}
<!-- {{$JobID}} -->
<div class="two wide column nowrap">
<div class="two wide column nowrap" style="width:10% !important;">
{{if eq .JobType "DEBUG"}}
<a class="title"
href="{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}{{if eq .ComputeResource "CPU/GPU"}}/cloudbrain/{{$JobID}}{{else}}/modelarts/notebook/{{$JobID}}{{end}}"
title="{{.DisplayJobName}}" style="font-size: 14px;">
title="{{.DisplayJobName}}" style="font-size: 14px;padding-right:0px">
<span class="fitted"
style="width: 90%;vertical-align: middle;">{{.DisplayJobName}}</span>
</a>
{{else if or (eq .JobType "SNN4IMAGENET") (eq .JobType "BRAINSCORE")}}
<a class="title"
href="{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}/cloudbrain/benchmark/{{$JobID}}"
title="{{.DisplayJobName}}" style="font-size: 14px;">
title="{{.DisplayJobName}}" style="font-size: 14px;padding-right:0px">
<span class="fitted"
style="width: 90%;vertical-align: middle;">{{.DisplayJobName}}</span>
</a>
{{else if eq .JobType "INFERENCE"}}
<a class="title"
href="{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}/modelarts/inference-job/{{$JobID}}"
href="{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}/{{if eq .Cloudbrain.Type 1}}modelarts{{else if eq .Cloudbrain.Type 0}}cloudbrain{{end}}/inference-job/{{$JobID}}"
title="{{.DisplayJobName}}" style="font-size: 14px;">
<span class="fitted"
style="width: 90%;vertical-align: middle;">{{.DisplayJobName}}</span>
@@ -103,26 +115,27 @@
{{else if eq .JobType "TRAIN"}}
<a class="title"
href="{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}{{if eq .Cloudbrain.Type 0}}/cloudbrain{{else if eq .Cloudbrain.Type 1}}/modelarts{{else if eq .Cloudbrain.Type 2}}/grampus{{end}}/train-job/{{$JobID}}"
title="{{.DisplayJobName}}" style="font-size: 14px;">
title="{{.DisplayJobName}}" style="font-size: 14px;padding-right:0px">
<span class="fitted"
style="width: 90%;vertical-align: middle;">{{.DisplayJobName}}</span>
</a>
{{else if eq .JobType "BENCHMARK"}}
<a class="title"
href="{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}/cloudbrain/benchmark/{{$JobID}}"
title="{{.DisplayJobName}}" style="font-size: 14px;">
title="{{.DisplayJobName}}" style="font-size: 14px;padding-right:0px">
<span class="fitted"
style="width: 90%;vertical-align: middle;">{{.DisplayJobName}}</span>
</a>
{{end}}
</div>
<!-- 任务类型 -->
<div class="one wide column text center nowrap">
<span style="font-size: 12px;">{{.JobType}} </span>
<!-- 集群 -->
<div class="one wide column text center nowrap" style="width:6% !important;">
<span
style="font-size: 12px;">{{if .Cluster}}{{.Cluster}}{{else}}--{{end}}</span>
</div>
<!-- 任务状态 -->
<div class="two wide column text center nowrap"
style="padding-left: 2.2rem !important; width: 10% !important;">
style="width: 6% !important;">
<span class="job-status" id="{{$JobID}}"
data-repopath='{{.Repo.OwnerName}}/{{.Repo.Name}}{{if eq .JobType "DEBUG"}}{{if eq .ComputeResource "CPU/GPU"}}/cloudbrain{{else}}/modelarts/notebook{{end}}{{else if eq .JobType "INFERENCE"}}/modelarts/inference-job{{else if eq .JobType "TRAIN"}}/modelarts/train-job{{else if eq .JobType "BENCHMARK"}}/cloudbrain{{end}}'
data-jobid="{{$JobID}}" data-version="{{.VersionName}}">
@@ -131,23 +144,39 @@
style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span>
</span>
</div>
<!-- 任务类型 -->
<div class="one wide column text center nowrap" style="width: 6% !important;">
<span style="font-size: 12px;">{{.JobType}} </span>
</div>
<!-- 任务创建时间 -->
<div class="two wide column text center nowrap" style="width: 10% !important;">
<div class="two wide column text center nowrap" style="width: 8% !important;">
<span style="font-size: 12px;"
class="">{{TimeSinceUnix1 .Cloudbrain.CreatedUnix}}</span>
</div>
<!-- 任务运行时间 -->
<div class="one wide column text center nowrap">
<div class="one wide column text center nowrap" style="width: 5% !important;">
<span style="font-size: 12px;"
id="duration-{{$JobID}}">{{if .TrainJobDuration}}{{.TrainJobDuration}}{{else}}--{{end}}</span>
</div>
<!-- 计算资源 -->
<div class="one wide column text center nowrap">
<div class="one wide column text center nowrap" style="width: 5% !important;">
<span
style="font-size: 12px;">{{if .ComputeResource}}{{.ComputeResource}}{{else}}--{{end}}</span>
</div>
<!-- 智算中心 -->
<div class="one wide column text center nowrap" style="width:8% !important;">
<span
style="font-size: 12px;">{{if .AiCenter}}{{.AiCenter}}{{else}}--{{end}}</span>
</div>
<!-- XPU类型 -->
<div class="one wide column text center nowrap" style="width:8% !important;">
<span style="font-size: 12px;" title="{{.CardType}}">
{{if .CardType}}{{.CardType}}{{else}}--{{end}}
</span>
</div>
<!-- 创建者 -->
<div class="one wide column text center nowrap">
<div class="one wide column text center nowrap" style="width:4% !important;">
{{if .User.Name}}
<a href="{{AppSubUrl}}/{{.User.Name}}" title="{{.User.Name}}"><img
class="ui avatar image" src="{{.User.RelAvatarLink}}"></a>
@@ -157,16 +186,24 @@
{{end}}
</div>
<!-- 项目 -->
<div class="two wide column text center nowrap">
<div class="two wide column text center nowrap" style="width:10% !important;">
<a href="{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}"
title="{{.Repo.OwnerName}}/{{.Repo.Alias}}">{{.Repo.OwnerName}}/{{.Repo.Alias}}</a>
</div>
<!-- 云脑侧名称 -->
<div class="two wide column text center nowrap"
style="overflow: hidden;text-overflow:ellipsis;">
<span class="fitted" title="{{.JobName}}">{{.JobName}}</span>
style="overflow: hidden;text-overflow:ellipsis;width:10% !important;">
<span class="ui poping up clipboard" data-position="top center" id="clipboard-btn" style="cursor:pointer"
data-clipboard-text="{{.JobName}}"
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"
>
<span class="fitted" title="{{.JobName}}">{{.JobName}}</span>
</span>
</div>
<div class="two wide column text center nowrap" style="width: 17.5%!important;">
<div class="two wide column text center nowrap" style="width: 14%!important;">
{{if eq .JobType "DEBUG"}}
<div class="ui compact buttons">
<form id="debugAgainForm-{{$JobID}}">
@@ -235,36 +272,37 @@
<div class="ui grid stackable item">
<div class="row">
<!-- 任务名 -->
<div class="two wide column nowrap">
<div class="two wide column nowrap" style="width:10% !important;">
{{if eq .JobType "DEBUG"}}
<a class="title" href="" title="{{.DisplayJobName}}" style="font-size: 14px;">
<a class="title" href="" title="{{.DisplayJobName}}" style="font-size: 14px;padding-right:0px">
<span class="fitted"
style="width: 90%;vertical-align: middle;">{{.DisplayJobName}}</span>
</a>
{{else if eq .JobType "INFERENCE"}}
<a class="title" href="" title="{{.DisplayJobName}}" style="font-size: 14px;">
<a class="title" href="" title="{{.DisplayJobName}}" style="font-size: 14px;padding-right:0px">
<span class="fitted"
style="width: 90%;vertical-align: middle;">{{.DisplayJobName}}</span>
</a>
{{else if eq .JobType "TRAIN"}}
<a class="title" href="" title="{{.DisplayJobName}}" style="font-size: 14px;">
<a class="title" href="" title="{{.DisplayJobName}}" style="font-size: 14px;padding-right:0px">
<span class="fitted"
style="width: 90%;vertical-align: middle;">{{.DisplayJobName}}</span>
</a>
{{else if eq .JobType "BENCHMARK"}}
<a class="title" href="" title="{{.DisplayJobName}}" style="font-size: 14px;">
<a class="title" href="" title="{{.DisplayJobName}}" style="font-size: 14px;padding-right:0px">
<span class="fitted"
style="width: 90%;vertical-align: middle;">{{.DisplayJobName}}</span>
</a>
{{end}}
</div>
<!-- 任务类型 -->
<div class="one wide column text center nowrap">
<span style="font-size: 12px;">{{.JobType}} </span>
<!-- 集群 -->
<div class="one wide column text center nowrap" style="width:6% !important;">
<span
style="font-size: 12px;">{{if .Cluster}}{{.Cluster}}{{else}}--{{end}}</span>
</div>
<!-- 任务状态 -->
<div class="two wide column text center nowrap"
style="padding-left: 2.2rem !important; width: 10% !important;">
style="width: 6% !important;">
<span class="job-status" id="{{$JobID}}" data-jobid="{{$JobID}}"
data-version="{{.VersionName}}">
<span><i id="{{$JobID}}-icon" style="vertical-align: middle;"
@@ -272,23 +310,39 @@
style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span>
</span>
</div>
<!-- 任务类型 -->
<div class="one wide column text center nowrap" style="width:6% !important;">
<span style="font-size: 12px;">{{.JobType}} </span>
</div>
<!-- 任务创建时间 -->
<div class="two wide column text center nowrap" style="width: 10% !important;">
<div class="two wide column text center nowrap" style="width: 8% !important;">
<span style="font-size: 12px;"
class="">{{TimeSinceUnix1 .Cloudbrain.CreatedUnix}}</span>
</div>
<!-- 任务运行时间 -->
<div class="one wide column text center nowrap">
<div class="one wide column text center nowrap" style="width:5% !important;">
<span style="font-size: 12px;"
id="duration-{{$JobID}}">{{if .TrainJobDuration}}{{.TrainJobDuration}}{{else}}--{{end}}</span>
</div>
<!-- 计算资源 -->
<div class="one wide column text center nowrap">
<div class="one wide column text center nowrap" style="width:5% !important;">
<span
style="font-size: 12px;">{{if .ComputeResource}}{{.ComputeResource}}{{else}}--{{end}}</span>
</div>
<!-- 智算中心 -->
<div class="one wide column text center nowrap" style="width:8% !important;">
<span
style="font-size: 12px;">{{if .AiCenter}}{{.AiCenter}}{{else}}--{{end}}</span>
</div>
<!-- XPU类型 -->
<div class="one wide column text center nowrap" style="width:8% !important;">
<span style="font-size: 12px;" title="{{.CardType}}">
{{if .CardType}}{{.CardType}}{{else}}--{{end}}
</span>
</div>
<!-- 创建者 -->
<div class="one wide column text center nowrap">
<div class="one wide column text center nowrap" style="width:4% !important;">
{{if .User.Name}}
<a href="{{AppSubUrl}}/{{.User.Name}}" title="{{.User.Name}}"><img
class="ui avatar image" src="{{.User.RelAvatarLink}}"></a>
@@ -298,15 +352,24 @@
{{end}}
</div>
<!-- 项目 -->
<div class="two wide column text center nowrap">
<div class="two wide column text center nowrap" style="width:10% !important;">
<a href="" title="">--</a>
</div>
<!-- 云脑侧名称 -->
<div class="two wide column text center nowrap"
style="overflow: hidden;text-overflow:ellipsis;">
<span class="fitted">{{.JobName}}</span>
style="overflow: hidden;text-overflow:ellipsis;width:10% !important;">
<span class="ui poping up clipboard" data-position="top center" id="clipboard-btn" style="cursor:pointer"
data-clipboard-text="{{.JobName}}"
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"
>
<span class="fitted" title="{{.JobName}}">{{.JobName}}</span>
</span>
</div>
<div class="two wide column text center nowrap" style="width: 17.5%!important;">
<div class="two wide column text center nowrap" style="width: 14%!important;">
{{if eq .JobType "DEBUG"}}
<div class="ui compact buttons">
<form id="debugAgainForm-{{$JobID}}">


+ 1
- 1
templates/admin/cloudbrain/search_dashboard.tmpl View File

@@ -15,7 +15,7 @@
</div>
</div>
</div>
<div class="ui container" style="width: 80%;">
<div class="ui container" style="width: 90%;">
<div class="ui grid">
<div class="row">
<div class="ui {{if $.PageIsUserCloudBrain}}sixteen{{else}}six{{end}} wide column" style="margin: 1rem 0;" id="userCloud">


+ 2
- 2
templates/admin/dataset/list.tmpl View File

@@ -35,7 +35,7 @@
{{range .Datasets}}
<tr>
<td>{{.ID}}</td>
<td style="display: flex;align-items: center;"><a href="{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Alias}}/datasets">{{.Title}}</a>{{if .Recommend}}<img src="/img/jian.svg" style="margin-left: 0.5rem;">{{end}}</td>
<td style="display: flex;align-items: center;"><a href="{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}/datasets">{{.Title}}</a>{{if .Recommend}}<img src="/img/jian.svg" style="margin-left: 0.5rem;">{{end}}</td>
<td><i class="fa fa{{if .IsPrivate}}-check{{end}}-square-o"></i></td>
<td><span title="{{.CreatedUnix.FormatLong}}">{{.CreatedUnix.FormatShort}}</span></td>
<td>{{if .Recommend}}<span class="set_dataset" style="color: rgb(250, 140, 22);cursor: pointer;" data-url="{{$.Link}}/{{.ID}}/action/unrecommend">{{$.i18n.Tr "admin.datasets.unrecommend"}}</span>{{else}}<span class="set_dataset" style="color: rgb(19, 194, 141);cursor: pointer;" data-url="{{$.Link}}/{{.ID}}/action/recommend">{{$.i18n.Tr "admin.datasets.recommend"}}</span>{{end}}</td>
@@ -48,4 +48,4 @@
{{template "base/paginate" .}}
</div>
</div>
{{template "base/footer" .}}
{{template "base/footer" .}}

+ 5
- 0
templates/base/head.tmpl View File

@@ -109,6 +109,11 @@
],
{{end}}
};
{{if .IsSigned}}
window.sessionStorage.setItem('_csrf', '{{.CsrfToken}}');
{{else}}
window.sessionStorage.removeItem('_csrf');
{{end}}
</script>
<link rel="shortcut icon" href="{{StaticUrlPrefix}}/img/favicon.png">
<link rel="mask-icon" href="{{StaticUrlPrefix}}/img/openi-safari.svg" color="#609926">


+ 5
- 0
templates/base/head_course.tmpl View File

@@ -109,6 +109,11 @@
],
{{end}}
};
{{if .IsSigned}}
window.sessionStorage.setItem('_csrf', '{{.CsrfToken}}');
{{else}}
window.sessionStorage.removeItem('_csrf');
{{end}}
</script>
<link rel="shortcut icon" href="{{StaticUrlPrefix}}/img/favicon.png">
<link rel="mask-icon" href="{{StaticUrlPrefix}}/img/openi-safari.svg" color="#609926">


+ 5
- 0
templates/base/head_fluid.tmpl View File

@@ -109,6 +109,11 @@
],
{{end}}
};
{{if .IsSigned}}
window.sessionStorage.setItem('_csrf', '{{.CsrfToken}}');
{{else}}
window.sessionStorage.removeItem('_csrf');
{{end}}
</script>
<link rel="shortcut icon" href="{{StaticUrlPrefix}}/img/favicon.png">
<link rel="mask-icon" href="{{StaticUrlPrefix}}/img/openi-safari.svg" color="#609926">


+ 5
- 0
templates/base/head_home.tmpl View File

@@ -109,6 +109,11 @@
],
{{end}}
};
{{if .IsSigned}}
window.sessionStorage.setItem('_csrf', '{{.CsrfToken}}');
{{else}}
window.sessionStorage.removeItem('_csrf');
{{end}}
</script>
<link rel="shortcut icon" href="{{StaticUrlPrefix}}/img/favicon.png">
<link rel="mask-icon" href="{{StaticUrlPrefix}}/img/openi-safari.svg" color="#609926">


+ 4
- 2
templates/base/head_navbar.tmpl View File

@@ -42,7 +42,8 @@
<a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a>
<a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a>
{{if .IsOperator}}
<a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a>
{{/* <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> */}}
<a class="item" href="{{AppSubUrl}}/kanban/index.html" target="_blank" rel="opener">{{.i18n.Tr "explore.data_analysis"}}</a>
{{end}}
<a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi.repo"}}</a>
</div>
@@ -73,7 +74,8 @@
<a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a>
<a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a>
{{if .IsOperator}}
<a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a>
{{/* <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> */}}
<a class="item" href="{{AppSubUrl}}/kanban/index.html" target="_blank" rel="opener">{{.i18n.Tr "explore.data_analysis"}}</a>
{{end}}
<a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi.repo"}}</a>
</div>


+ 4
- 2
templates/base/head_navbar_fluid.tmpl View File

@@ -41,7 +41,8 @@
<a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a>
<a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a>
{{if .IsOperator}}
<a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a>
{{/* <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> */}}
<a class="item" href="{{AppSubUrl}}/kanban/index.html" target="_blank" rel="opener">{{.i18n.Tr "explore.data_analysis"}}</a>
{{end}}
<a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi.repo"}}</a>
</div>
@@ -71,7 +72,8 @@
<a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a>
<a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a>
{{if .IsOperator}}
<a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a>
{{/* <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> */}}
<a class="item" href="{{AppSubUrl}}/kanban/index.html" target="_blank" rel="opener">{{.i18n.Tr "explore.data_analysis"}}</a>
{{end}}
<a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi.repo"}}</a>
</div>


+ 4
- 2
templates/base/head_navbar_home.tmpl View File

@@ -33,7 +33,8 @@
<a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a>
<a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a>
{{if .IsOperator}}
<a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a>
{{/* <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> */}}
<a class="item" href="{{AppSubUrl}}/kanban/index.html" target="_blank" rel="opener">{{.i18n.Tr "explore.data_analysis"}}</a>
{{end}}
<a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi.repo"}}</a>
</div>
@@ -64,7 +65,8 @@
<a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a>
<a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a>
{{if .IsOperator}}
<a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a>
{{/* <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> */}}
<a class="item" href="{{AppSubUrl}}/kanban/index.html" target="_blank" rel="opener">{{.i18n.Tr "explore.data_analysis"}}</a>
{{end}}
<a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi.repo"}}</a>
</div>


+ 4
- 2
templates/base/head_navbar_pro.tmpl View File

@@ -43,7 +43,8 @@
<a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a>
<a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a>
{{if .IsOperator}}
<a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a>
{{/* <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> */}}
<a class="item" href="{{AppSubUrl}}/kanban/index.html" target="_blank" rel="opener">{{.i18n.Tr "explore.data_analysis"}}</a>
{{end}}
<a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi.repo"}}</a>
</div>
@@ -74,7 +75,8 @@
<a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a>
<a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a>
{{if .IsOperator}}
<a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a>
{{/* <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> */}}
<a class="item" href="{{AppSubUrl}}/kanban/index.html" target="_blank" rel="opener">{{.i18n.Tr "explore.data_analysis"}}</a>
{{end}}
<a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi.repo"}}</a>
</div>


+ 5
- 0
templates/base/head_pro.tmpl View File

@@ -109,6 +109,11 @@
],
{{end}}
};
{{if .IsSigned}}
window.sessionStorage.setItem('_csrf', '{{.CsrfToken}}');
{{else}}
window.sessionStorage.removeItem('_csrf');
{{end}}
</script>
<link rel="shortcut icon" href="{{StaticUrlPrefix}}/img/favicon.png">
<link rel="mask-icon" href="{{StaticUrlPrefix}}/img/openi-safari.svg" color="#609926">


+ 1
- 0
templates/custom/select_dataset_train.tmpl View File

@@ -9,6 +9,7 @@
{{end}} -->
<label class="label-fix-width" style="font-weight: normal;">{{if .benchmarkMode}}{{.i18n.Tr "repo.model_manager"}}{{else}}{{.i18n.Tr "dataset.dataset"}}{{end}}</label>
<input type="hidden" name="attachment" :value="dataset_uuid">
<input type="hidden" name="dataset_name" :value="dataset_name">
<input class="disabled" type="text" :value="dataset_name" required onfocus="this.blur();" style="width: 48.5%;">
<el-button type="text" @click="dialogVisible = true" icon="el-icon-plus" style="color: #0366d6;">
{{if .benchmarkMode}}{{.i18n.Tr "repo.modelarts.infer_job.select_model"}}{{else}}{{.i18n.Tr "dataset.select_dataset"}}{{end}}


+ 8
- 5
templates/explore/dataset_list.tmpl View File

@@ -24,9 +24,9 @@
<div class="ui sixteen wide mobile ten wide tablet ten wide computer colum">
{{range .Datasets}}
<div class="item">
<div class="ui header">
<a class="name" href="{{.Repo.Link}}/datasets">
{{.Repo.OwnerName}} / {{.Repo.Alias}}
<div class="ui header" style="display: flex;">
<a class="name dataset-title-a" title="{{.Title}}" href="{{.Repo.Link}}/datasets">
{{.Title}}
</a>
<div class="ui right metas">
{{if .Task}}
@@ -40,7 +40,7 @@
</div>
<div class="description">
{{if .Description}}
<p class="has-emoji">{{.Description}}</p>
<p class="has-emoji" style="word-break: break-all;">{{.Description}}</p>
{{else if .Repo.DescriptionHTML}}
<p class="has-emoji">{{.Repo.DescriptionHTML}}</p>
{{end}}
@@ -53,4 +53,7 @@
</div>
{{end}}
</div>
</div>
</div>
<script>
console.log({{.Datasets}})
</script>

+ 1
- 1
templates/org/create.tmpl View File

@@ -48,7 +48,7 @@
<button class="ui green button">
{{.i18n.Tr "org.create_org"}}
</button>
<a class="ui button" href="{{AppSubUrl}}/">{{.i18n.Tr "cancel"}}</a>
<a class="ui button" href="javascript:history.go(-1)">{{.i18n.Tr "cancel"}}</a>
</div>
</div>
</form>


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

@@ -69,8 +69,8 @@
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.job_name"}}</label>
<input style="width: 80%;" name="display_job_name" id="trainjob_job_name"
placeholder={{.i18n.Tr "repo.modelarts.train_job.job_name"}} value="{{.display_job_name}}"
tabindex="3" autofocus required maxlength="254">
<span class="tooltips" style="display: block;margin-left:11.5rem;">{{.i18n.Tr "cloudbrain.job_name_rule"}}</span>
tabindex="3" autofocus required maxlength="36">
<span class="tooltips" style="display: block;margin-left:11.5rem;">{{.i18n.Tr "repo.cloudbrain_jobname_err"}}</span>
</div>
<div class="required min_title inline field">
<label class="label-fix-width" style="font-weight: normal;"
@@ -165,8 +165,8 @@
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.job_name"}}</label>
<input style="width: 80%;" name="display_job_name" id="trainjob_job_name"
placeholder={{.i18n.Tr "repo.modelarts.train_job.job_name"}} value="{{.display_job_name}}"
tabindex="3" autofocus required maxlength="254">
<span class="tooltips" style="display: block;margin-left: 11.5rem;">{{.i18n.Tr "cloudbrain.job_name_rule"}}</span>
tabindex="3" autofocus required maxlength="36">
<span class="tooltips" style="display: block;margin-left: 11.5rem;">{{.i18n.Tr "repo.cloudbrain_jobname_err"}}</span>
</div>
<div class="min_title inline field">
<label class="label-fix-width" style="font-weight: normal;"
@@ -331,7 +331,7 @@
identifier: 'display_job_name',
rules: [
{
type: 'regExp[/^[a-zA-Z0-9-_]{1,64}[a-zA-Z0-9_]$/]',
type: 'regExp[/^[a-z0-9][a-z0-9-_]{1,34}[a-z0-9-]$/]',
promt: ''
}
]


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

@@ -353,7 +353,15 @@

<td class="ti-text-form-content">
<div class="text-span text-span-w" id="{{.VersionName}}-mirror">
{{.Image}}
<span class="ui poping up clipboard" data-position="top center" id="clipboard-btn" style="cursor:pointer"
data-clipboard-text="{{.Image}}"
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"
>
<span title="{{.Image}}">{{.Image}}</span>
</span>
</div>
</td>
</tr>


+ 129
- 106
templates/repo/cloudbrain/inference/new.tmpl View File

@@ -58,18 +58,16 @@
<form 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="">
<input type="hidden" id="ai_flaver_name" name="flaver_names" value="">
{{if $.model_version}}
<input type="hidden" id="ai_model_version" name="model_version" value="{{$.model_version}}">
{{else}}
<input type="hidden" id="ai_image_name" value="{{.image}}">
<input type="hidden" id="ai_model_version" name="model_version" value="">
{{end}}
{{if $.label_names}}
<input type="hidden" id="ai_model_label" name="label_names" value="{{$.label_names}}">
{{else}}
<input type="hidden" id="ai_model_label" name="label_names" value="">
{{end}}

<input type="hidden" id="failed_train_url" value="{{$.train_url}}">
<input type="hidden" id="failed_model_name" value="{{$.model_name}}">
<input type="hidden" id="failed_model_version" value="{{$.model_version}}">
<input type="hidden" id="failed_ckpt_name" value="{{$.ckpt_name}}">
<input type="hidden" id="failed_train_url" value="{{$.train_url}}">
<input type="hidden" id="fail_dataset_name" value="{{$.dataset_name}}">
<input type="hidden" id="fail_dataset_uuid" value="{{$.attachment}}">
<h4 class="unite title ui header ">{{.i18n.Tr "repo.modelarts.train_job.basic_info"}}:</h4>
<div class="required min_title inline field">
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "cloudbrain.compute_resource"}}</label>
@@ -96,13 +94,17 @@
</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>
<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}}" onkeyup="this.value=this.value.replace(/[, ]/g,'')" tabindex="3" autofocus required maxlength="64">
<span class="tooltips" style="margin-left:11.5rem;display: block;">{{.i18n.Tr "cloudbrain.job_name_rule"}}</span>
<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}}" onkeyup="this.value=this.value.replace(/[, ]/g,'')" tabindex="3" autofocus required maxlength="36">
<span class="tooltips" style="margin-left:11.5rem;display: block;">{{.i18n.Tr "repo.cloudbrain_jobname_err"}}</span>
</div>

<div class="unite min_title inline field">
<label class="label-fix-width" style="font-weight: normal;" for="description">{{.i18n.Tr "repo.modelarts.train_job.description"}}</label>
{{if .description}}
<textarea style="width: 80%;" id="description" name="description" rows="3" maxlength="255" placeholder={{.i18n.Tr "repo.modelarts.train_job.new_place"}}>{{.description}}</textarea>
{{else}}
<textarea style="width: 80%;" id="description" name="description" rows="3" maxlength="255" placeholder={{.i18n.Tr "repo.modelarts.train_job.new_place"}} onchange="this.value=this.value.substring(0, 255)" onkeydown="this.value=this.value.substring(0, 255)" onkeyup="this.value=this.value.substring(0, 255)"></textarea>
{{end}}
</div>
<div class="ui divider"></div>

@@ -112,13 +114,8 @@
<div class="required eight wide field">
<label style="font-weight: normal;white-space: nowrap;width: 210px;text-align: right;">{{.i18n.Tr "repo.modelarts.infer_job.select_model"}}</label>
<div class="ui fluid search selection dropdown loading " id="select_model">
{{if $.ckpt_name}}
<input type="hidden" name="model_name" value="{{$.model_name}}" required>
<div class="text">{{$.model_name}}</div>
{{else}}
<input type="hidden" name="model_name" required>
<div class="text"></div>
{{end}}
<i class="dropdown icon"></i>
<div class="menu" id="model_name">
</div>
@@ -126,13 +123,8 @@
</div>
<div class="three wide field">
<div class="ui fluid search selection dropdown" id="select_model_version">
{{if $.ckpt_name}}
<input type="hidden" name="train_url" value="{{$.train_url}}" required>
<div class="text">{{$.model_version}}</div>
{{else}}
<input type="hidden" name="train_url" required>
<div class="text"></div>
{{end}}
<i class="dropdown icon"></i>
<div class="menu" id="model_name_version">
</div>
@@ -141,13 +133,8 @@
</div>
<div class="five wide field">
<div class="ui fluid search selection dropdown" id="select_model_checkpoint">
{{if $.ckpt_name}}
<input type="hidden" name="ckpt_name" value="{{$.ckpt_name}}" required>
<div class="text">{{$.ckpt_name}}</div>
{{else}}
<input type="hidden" name="ckpt_name" required>
<div class="text"></div>
{{end}}
<i class="dropdown icon"></i>
<div class="menu" id="model_checkpoint">
</div>
@@ -186,8 +173,21 @@
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "cloudbrain.gpu_type"}}</label>
<select id="cloudbrain_gpu_type" class="ui search width48 dropdown gpu-type" placeholder="选择GPU类型"
style='width:385px' name="gpu_type">
{{range .inference_gpu_types}}
<option value="{{.Queue}}">{{.Value}}</option>
{{if .gpu_type}}
{{range .inference_gpu_types}}
{{if eq $.gpu_type .Queue}}
<option value="{{.Queue}}">{{.Value}}</option>
{{end}}
{{end}}
{{range .inference_gpu_types}}
{{if ne $.gpu_type .Queue}}
<option value="{{.Queue}}">{{.Value}}</option>
{{end}}
{{end}}
{{else}}
{{range .inference_gpu_types}}
<option value="{{.Queue}}">{{.Value}}</option>
{{end}}
{{end}}
</select>
</div>
@@ -196,8 +196,8 @@
<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}}
<input style="width: 48.5%;" name="boot_file" id="trainjob_boot_file" value="{{.bootFile}}" tabindex="3" autofocus required maxlength="255" >
{{if .boot_file}}
<input style="width: 48.5%;" name="boot_file" id="trainjob_boot_file" value="{{.boot_file}}" tabindex="3" autofocus required maxlength="255" >
{{else}}
<input style="width: 48.5%;" name="boot_file" id="trainjob_boot_file" value="" tabindex="3" autofocus required maxlength="255" >
{{end}}
@@ -212,23 +212,8 @@
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.run_parameter"}}</label>
<span id="add_run_para" style="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>
<input id="store_run_para" type="hidden" name="run_para_list">
<div class="dynamic field" style="margin-top: 1rem;">
{{if ne 0 (len .params)}}
{{range $k ,$v := .params}}
<div class="two fields width85" id="para{{$k}}">
<div class="field">
<input type="text" name="shipping_first-name" value={{$v.Label}} required>
</div>
<div class="field">
<input type="text" name="shipping_last-name" value={{$v.Value}} required>
</div>
<span>
<i class="trash icon"></i>
</span>
<div class="dynamic field" style="margin-top: 1rem;" data-params="{{.run_para_list}}">

</div>
{{end}}
{{end}}
</div>
</div>

@@ -244,9 +229,22 @@
<div class="required min_title inline field">
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "cloudbrain.resource_specification"}}</label>
<select id="cloudbrain_resource_spec" class="ui search dropdown width80" placeholder="选择资源规格" name="resource_spec_id">
{{range .inference_resource_specs}}
<option name="resource_spec_id" value="{{.Id}}">
GPU数:{{.GpuNum}},CPU数:{{.CpuNum}},内存(MB):{{.MemMiB}},共享内存(MB):{{.ShareMemMiB}}</option>
{{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>
{{end}}
{{end}}
{{range .inference_resource_specs}}
{{if ne $.resource_spec_id .Id}}
<option value="{{.Id}}">GPU数:{{.GpuNum}},CPU数:{{.CpuNum}},内存(MB):{{.MemMiB}},共享内存(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>
{{end}}
{{end}}
</select>
</div>
@@ -270,27 +268,35 @@
const RepoLink = {{.RepoLink}}
let nameMap,nameList
// 获取模型列表和模型名称对应的模型版本
$.get(`${RepoLink}/modelmanage/query_model_for_predict?type=0`, (data) => {
$(document).ready(function(){
modelVersion()
modelCkpt()
nameMap = data.nameMap
nameList = data.nameList
let html = ''
nameList.forEach(element => {
html += `<div class="item" data-value=${element}>${element}</div>`
});
if(nameList.length!==0){
const initModelVersion = nameMap[nameList[0]][0]
const initTrainTaskInfo = JSON.parse(initModelVersion.TrainTaskInfo)
$('#model_name').append(html)
$("#select_model").dropdown('set text',nameList[0])
$("#select_model").dropdown('set value',nameList[0],nameList[0])
}

$('#select_model').removeClass("loading")
$.get(`${RepoLink}/modelmanage/query_model_for_predict?type=0`, (data) => {
nameMap = data.nameMap
nameList = data.nameList
let faildModelName = document.getElementById('failed_model_name').value
let html = ''
nameList.forEach(element => {
html += `<div class="item" data-value=${element}>${element}</div>`
});
if(nameList.length!==0){
$('#model_name').append(html)
if(faildModelName){
$("#select_model").dropdown('set text',faildModelName)
$("#select_model").dropdown('set value',faildModelName)
}else{
$("#select_model").dropdown('set text',nameList[0])
$("#select_model").dropdown('set value',nameList[0],nameList[0])
}
}
$('#select_model').removeClass("loading")
})
})
// 根据选中的模型名称获取相应的模型版本
function modelVersion(){
let faildModelVersion = $('#failed_model_version').val()
let faildTrainUrl = $('#failed_train_url').val()
$('#select_model').dropdown({
onChange: function(value, text, $selectedItem) {
$("#select_model_version").addClass("loading")
@@ -305,13 +311,20 @@
$("#select_model_version").removeClass("loading")
const initVersionText = $('#model_name_version div.item:first-child').text()
const initVersionValue = $('#model_name_version div.item:first-child').data('value')
$("#select_model_version").dropdown('set text',initVersionText)
$("#select_model_version").dropdown('set value',initVersionValue,initVersionText,$('#model_name_version div.item:first-child'))
if(faildModelVersion&&faildTrainUrl){
$("#select_model_version").dropdown('set text',faildModelVersion)
$("#select_model_version").dropdown('set value',faildTrainUrl,faildModelVersion,$('#model_name_version div.item:first-child'))
}else{
$("#select_model_version").dropdown('set text',initVersionText)
$("#select_model_version").dropdown('set value',initVersionValue,initVersionText,$('#model_name_version div.item:first-child'))
}
}
})
}
// 根据选中的模型版本获取相应的模型权重文件
function modelCkpt(){
let faildCkptName = $('#failed_ckpt_name').val()
$('#select_model_version').dropdown({
onChange: function(value, text, $selectedItem) {
const dataID = $selectedItem[0].getAttribute("data-id")
@@ -326,17 +339,19 @@
if(!element.IsDir && loadCheckpointFile.includes(ckptSuffix[ckptSuffix.length-1])){
html += `<div class="item" data-value=${element.FileName}>${element.FileName}</div>`
}

})
$('#model_checkpoint').append(html)
$("#select_model_checkpoint").removeClass("loading")
const initVersionText = $('#model_checkpoint div.item:first-child').text()
const initVersionValue = $('#model_checkpoint div.item:first-child').data('value')
$("#select_model_checkpoint").dropdown('set text',initVersionText)
$("#select_model_checkpoint").dropdown('set value',initVersionValue,initVersionText,$('#model_name_version div.item:first-child'))
if(faildCkptName){
$("#select_model_checkpoint").dropdown('set text',faildCkptName)
$("#select_model_checkpoint").dropdown('set value',faildCkptName,faildCkptName,$('#model_name_version div.item:first-child'))
}else{
$("#select_model_checkpoint").dropdown('set text',initVersionText)
$("#select_model_checkpoint").dropdown('set value',initVersionValue,initVersionText,$('#model_name_version div.item:first-child'))
}
})


$("input#ai_model_version").val(text)
$("input#ai_model_label").val(label)
}
@@ -354,56 +369,64 @@
$(this).popup('show')
});

$(document).ready(function(){
let params = $('.dynamic.field').data('params')
params&&params.parameter.forEach((item,index)=>{
Add_parameter(index,flag=true,item)
})
})
// 参数增加、删除、修改、保存
function Add_parameter(i){
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"}}> ' +
'</div> ' +
'<div class="field"> ' +
'<input type="text" name="shipping_last-name" required placeholder={{.i18n.Tr "repo.modelarts.train_job.parameter_value"}}>' +
'</div>'+
'<span>' +
'<i class="trash icon">' +
'</i>' +
'</span>' +
'</div>'
function Add_parameter(i,flag=false,paramsObject={}) {
let value = ''
value += `<div class="two fields width85" id= "para${i}">`
value += '<div class="field">'
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 += '</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 += '</div>'
value += '<span><i class="trash icon"></i></span>'
value += '</div>'
$(".dynamic.field").append(value)

}

$('#add_run_para').click(function(){
$('#add_run_para').click(function () {
var len = $(".dynamic.field .two.fields").length
Add_parameter(len)
});

$(".dynamic.field").on("click",".trash.icon", function() {
$(".dynamic.field").on("click", ".trash.icon", function () {
var index = $(this).parent().parent().index()
$(this).parent().parent().remove()
var len = $(".dynamic.field .two.fields").length
$(".dynamic.field .two.fields").each(function(){
$(".dynamic.field .two.fields").each(function () {
var cur_index = $(this).index()
$(this).attr('id', 'para' + cur_index)
})
});
function send_run_para(){

function send_run_para() {
var run_parameters = []
var msg = {}
$(".dynamic.field .two.fields").each(function(){
var para_name = $(this).find('input[name=shipping_first-name]').val()
var para_value = $(this).find('input[name=shipping_last-name]').val()
run_parameters.push({"label": para_name, "value": para_value})
$(".dynamic.field .two.fields").each(function () {
var para_name = $(this).find('input.shipping_first-name').val()
var para_value = $(this).find('input.shipping_last-name').val()
run_parameters.push({ "label": para_name, "value": para_value })
})
msg["parameter"] = run_parameters
msg = JSON.stringify(msg)
$('#store_run_para').val(msg)
}
function get_name(){
let name1=$("#engine_name .text").text()
let name2=$("#flaver_name .text").text()
$("input#ai_engine_name").val(name1)
$("input#ai_flaver_name").val(name2)

}
function validate(){
$('.ui.form')
.form({
@@ -421,7 +444,7 @@
identifier : 'display_job_name',
rules: [
{
type: 'regExp[/^[a-zA-Z0-9-_]{1,64}[^-]$/]',
type: 'regExp[/^[a-z0-9][a-z0-9-_]{1,34}[a-z0-9-]$/]',
}
]
},
@@ -472,9 +495,9 @@
document.getElementById("mask").style.display = "none"
}
}
validate();
$('.ui.create_train_job.green.button').click(function(e) {
send_run_para()
get_name()
validate()
send_run_para();
validate();
})
</script>

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

@@ -381,7 +381,15 @@

<td class="ti-text-form-content">
<div class="text-span text-span-w" id="{{.VersionName}}-mirror">
{{.Image}}
<span class="ui poping up clipboard" data-position="top center" id="clipboard-btn" style="cursor:pointer"
data-clipboard-text="{{.Image}}"
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"
>
<span title="{{.Image}}">{{.Image}}</span>
</span>
</div>
</td>
</tr>


+ 21
- 0
templates/repo/cloudbrain/new.tmpl View File

@@ -294,6 +294,27 @@
context.value = ''
$(".icon.icons").css("visibility", "hidden")
}
function validate(){
$('.ui.form').form({
on: 'blur',
fields: {
display_job_name:{
identifier : 'display_job_name',
rules: [
{
type: 'regExp[/^[a-z0-9][a-z0-9-_]{1,34}[a-z0-9-]$/]',
}
]
},
},
onSuccess: function(){
},
onFailure: function(e){
return false;
}
})
}
validate();
form.onsubmit = function (e) {
let value_task = $("input[name='display_job_name']").val()
let value_image = $("input[name='image']").val()


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

@@ -252,7 +252,9 @@
</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 class="redo icon redo-color"></i>
</span>
</div>
</span>
</span>
@@ -390,7 +392,15 @@

<td class="ti-text-form-content">
<div class="text-span text-span-w" id="{{.VersionName}}-mirror">
{{.Image}}
<span class="ui poping up clipboard" data-position="top center" id="clipboard-btn" style="cursor:pointer"
data-clipboard-text="{{.Image}}"
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"
>
<span title="{{.Image}}">{{.Image}}</span>
</span>
</div>
</td>
</tr>


+ 75
- 142
templates/repo/cloudbrain/trainjob/new.tmpl View File

@@ -89,8 +89,7 @@
<form 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="">
<input type="hidden" id="ai_flaver_name" name="flaver_names" value="">
<input type="hidden" id="ai_image_name" value="{{.image}}">
<h4 class="train-job-title ui header ">{{.i18n.Tr "repo.modelarts.train_job.basic_info"}}:</h4>
<div class="required unite min_title inline field">
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "cloudbrain.resource_cluster"}}</label>
@@ -133,18 +132,18 @@
<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="64">
<span class="tooltips" style="display: block;margin-left: 11.5rem;">{{.i18n.Tr "cloudbrain.job_name_rule"}}</span>
maxlength="36">
<span class="tooltips" style="display: block;margin-left: 11.5rem;">{{.i18n.Tr "repo.cloudbrain_jobname_err"}}</span>
</div>

<div class="inline min_title field">
<label class="label-fix-width" style="font-weight: normal;"
for="description">{{.i18n.Tr "repo.modelarts.train_job.description"}}</label>
<textarea style="width: 80%;" id="description" name="description" rows="3" maxlength="255"
placeholder={{.i18n.Tr "repo.modelarts.train_job.new_place"}}
onchange="this.value=this.value.substring(0, 255)"
onkeydown="this.value=this.value.substring(0, 255)"
onkeyup="this.value=this.value.substring(0, 255)"></textarea>
{{if .description}}
<textarea style="width: 80%;" id="description" name="description" rows="3" maxlength="255" placeholder={{.i18n.Tr "repo.modelarts.train_job.new_place"}}>{{.description}}</textarea>
{{else}}
<textarea style="width: 80%;" id="description" name="description" rows="3" maxlength="255" placeholder={{.i18n.Tr "repo.modelarts.train_job.new_place"}} onchange="this.value=this.value.substring(0, 255)" onkeydown="this.value=this.value.substring(0, 255)" onkeyup="this.value=this.value.substring(0, 255)"></textarea>
{{end}}
</div>
<div class="ui divider"></div>

@@ -179,13 +178,25 @@
<option name="job_type" value="TRAIN">TRAIN</option>
</select>
</div>

<div class="required min_title inline field">
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "cloudbrain.gpu_type"}}</label>
<select id="cloudbrain_gpu_type" class="ui search width806 dropdown gpu-type" placeholder="选择GPU类型"
style='width:385px' name="gpu_type">
{{range .train_gpu_types}}
<option value="{{.Queue}}">{{.Value}}</option>
{{if .gpu_type}}
{{range .train_gpu_types}}
{{if eq $.gpu_type .Queue}}
<option value="{{.Queue}}">{{.Value}}</option>
{{end}}
{{end}}
{{range .train_gpu_types}}
{{if ne $.gpu_type .Queue}}
<option value="{{.Queue}}">{{.Value}}</option>
{{end}}
{{end}}
{{else}}
{{range .train_gpu_types}}
<option value="{{.Queue}}">{{.Value}}</option>
{{end}}
{{end}}
</select>
</div>
@@ -195,8 +206,8 @@

<div class="inline field min_title required">
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.start_file"}}</label>
{{if .bootFile}}
<input style="width: 48.5%;" name="boot_file" id="trainjob_boot_file" value="{{.bootFile}}"
{{if .boot_file}}
<input style="width: 48.5%;" name="boot_file" id="trainjob_boot_file" value="{{.boot_file}}"
tabindex="3" autofocus required maxlength="255">
{{else}}
<input style="width: 48.5%;" name="boot_file" id="trainjob_boot_file" value="" tabindex="3"
@@ -220,35 +231,30 @@
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>
<input id="store_run_para" type="hidden" name="run_para_list">
<div class="dynamic field" style="margin-top: 1rem;">
{{if .params}}
{{if ne 0 (len .params)}}
{{range $k ,$v := .params}}
<div class="two fields width85" id="para{{$k}}">
<div class="field">
<input type="text" name="shipping_first-name" value={{$v.Label}} required>
</div>
<div class="field">
<input type="text" name="shipping_last-name" value={{$v.Value}} required>
</div>
<span>
<i class="trash icon"></i>
</span>

</div>
{{end}}
{{end}}
{{end}}
<div class="dynamic field" style="margin-top: 1rem;" data-params="{{.run_para_list}}">
</div>
</div>

<div class="required min_title inline field">
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "cloudbrain.resource_specification"}}</label>
<select id="cloudbrain_resource_spec" class="ui search dropdown" placeholder="选择资源规格"
style='width:385px' name="resource_spec_id">
{{range .train_resource_specs}}
<option name="resource_spec_id" value="{{.Id}}">
GPU数:{{.GpuNum}},CPU数:{{.CpuNum}},内存(MB):{{.MemMiB}},共享内存(MB):{{.ShareMemMiB}}</option>
{{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>
{{end}}
{{end}}
{{range .train_resource_specs}}
{{if ne $.resource_spec_id .Id}}
<option value="{{.Id}}">GPU数:{{.GpuNum}},CPU数:{{.CpuNum}},内存(MB):{{.MemMiB}},共享内存(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>
{{end}}
{{end}}
</select>
</div>
@@ -281,34 +287,35 @@
case 13:return false;
}
});
let sever_num = $('#trainjob_work_server_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)
}
$(document).ready(function(){
let params = $('.dynamic.field').data('params')
params&&params.parameter.forEach((item,index)=>{
Add_parameter(index,flag=true,item)
})
})
// 参数增加、删除、修改、保存
function Add_parameter(i) {
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"}}> ' +
'</div> ' +
'<div class="field"> ' +
'<input type="text" name="shipping_last-name" required placeholder={{.i18n.Tr "repo.modelarts.train_job.parameter_value"}}>' +
'</div>' +
'<span>' +
'<i class="trash icon">' +
'</i>' +
'</span>' +
'</div>'
function Add_parameter(i,flag=false,paramsObject={}) {
let value = ''
value += `<div class="two fields width85" id= "para${i}">`
value += '<div class="field">'
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 += '</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 += '</div>'
value += '<span><i class="trash icon"></i></span>'
value += '</div>'
$(".dynamic.field").append(value)

}

$('#add_run_para').click(function () {
@@ -326,80 +333,13 @@
})
});

$('.ui.parameter.green.button').click(function () {
var parameters = [];
$('table tr').each(function () {
$(this).find('td:eq(1)').each(function () {
parameters.push($(this).text());
})
$(this).find('input').each(function () {
parameters.push($(this).text())
})

});
$('.ui.parameter.modal')
.modal('hide');
for (var i = 2; i < parameters.length; i++) {
switch (i) {
// 数据集uuid待完成
// case (2):
// console.log(1)
// break;
// $("#trainjob_datasets").val(parameters[i]);
// console.log($("#trainjob_datasets").val())
case (3):
$("input[name='boot_file']").val(parameters[i]);
break;
case (4):
var para = parameters[i].split(" ")
for (var j = 0; j < para.length; j++) {
var para_name = para[j].split('=')[0]
var para_value = para[j].split('=')[1]
var len = $(".dynamic.field .two.fields").length
Add_parameter(len)
var pid = 'para' + len
$(".dynamic.field" + " #" + pid + "").find("input[name=shipping_first-name]").val(para_name)
$(".dynamic.field" + " #" + pid + "").find("input[name=shipping_last-name]").val(para_value)
}
break;
// 数据集pool_id待完成
// case (5):
// $("select[name='pool_id']").val(parameters[i]);
// break;
case (6):
$("input[name='work_server_number']").val(parameters[i]);
break;
}
}
})

$('.ui.save.checkbox').click(function () {
$(this).checkbox({
onChange: function () {
if ($('.ui.save.checkbox').checkbox('is checked')) {
$('#save_para').removeClass("disabled")

} else {
$('#save_para').addClass("disabled")
}
}
});
})

$('.question.circle.icon').hover(function () {
$(this).popup('show')
});

$(".item.active.parameter_config").click(function () {
$('.ui.parameter.modal')
.modal('setting', 'closable', false)
.modal('show');
})

$('.ui.deny.button').click(function () {
$('.ui.parameter.modal')
.modal('hide');
})
$('select.dropdown')
.dropdown();

@@ -420,7 +360,7 @@
identifier: 'display_job_name',
rules: [
{
type: 'regExp[/^[a-zA-Z0-9-_]{1,64}[a-zA-Z0-9_]$/]',
type: 'regExp[/^[a-z0-9][a-z0-9-_]{1,34}[a-z0-9-]$/]',
}
]
},
@@ -468,24 +408,17 @@
var run_parameters = []
var msg = {}
$(".dynamic.field .two.fields").each(function () {
var para_name = $(this).find('input[name=shipping_first-name]').val()
var para_value = $(this).find('input[name=shipping_last-name]').val()
var para_name = $(this).find('input.shipping_first-name').val()
var para_value = $(this).find('input.shipping_last-name').val()
run_parameters.push({ "label": para_name, "value": para_value })
})
msg["parameter"] = run_parameters
msg = JSON.stringify(msg)
$('#store_run_para').val(msg)
}
function get_name() {
let name1 = $("#engine_name .text").text()
let name2 = $("#flaver_name .text").text()
$("input#ai_engine_name").val(name1)
$("input#ai_flaver_name").val(name2)

}
validate();
$('.ui.create_train_job.green.button').click(function (e) {
get_name()
send_run_para()
validate()
send_run_para();
validate();
})
</script>

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

@@ -384,7 +384,15 @@

<td class="ti-text-form-content">
<div class="text-span text-span-w" id="{{.VersionName}}-mirror">
{{.Image}}
<span class="ui poping up clipboard" data-position="top center" id="clipboard-btn" style="cursor:pointer"
data-clipboard-text="{{.Image}}"
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"
>
<span title="{{.Image}}">{{.Image}}</span>
</span>
</div>
</td>
</tr>


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

@@ -176,7 +176,7 @@
<button class="ui green button" id="submit_reponame">
{{.i18n.Tr "repo.create_repo"}}
</button>
<a class="ui button" href="{{AppSubUrl}}/">{{.i18n.Tr "cancel"}}</a>
<a class="ui button" href="javascript:history.go(-1)">{{.i18n.Tr "cancel"}}</a>
</div>
</div>
</form>


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

@@ -386,7 +386,7 @@
{{$.CsrfTokenHtml}}
{{if .CanDel}}
<a id="ai-stop-{{.Cloudbrain.ID}}"
class='ui basic ai_stop {{if eq .Status "STOPPED" "FAILED" "START_FAILED" "STOPPING" "CREATING" "STARTING" "SUCCEEDED" "CREATE_FAILED"}}disabled {{else}}blue {{end}}button'
class='ui basic ai_stop {{if eq .Status "STOPPED" "FAILED" "START_FAILED" "STOPPING" "CREATING" "STARTING" "SUCCEEDED" "CREATE_FAILED" "DELETED"}}disabled {{else}}blue {{end}}button'
data-repopath="{{$.RepoLink}}{{if eq .ComputeResource "CPU/GPU"}}/cloudbrain{{else}}/modelarts/notebook{{end}}/{{.Cloudbrain.ID}}/stop"
data-jobid="{{.Cloudbrain.ID}}">
{{$.i18n.Tr "repo.stop"}}
@@ -405,7 +405,7 @@
{{$.CsrfTokenHtml}}
{{if .CanDel}}
<a id="ai-delete-{{.Cloudbrain.ID}}"
class='ui basic ai_delete {{if eq .Status "STOPPED" "FAILED" "START_FAILED" "SUCCEEDED" "CREATE_FAILED"}}blue {{else}}disabled {{end}}button'
class='ui basic ai_delete {{if eq .Status "STOPPED" "FAILED" "START_FAILED" "SUCCEEDED" "CREATE_FAILED" "DELETED"}}blue {{else}}disabled {{end}}button'
style="border-radius: .28571429rem;">
{{$.i18n.Tr "repo.delete"}}
</a>
@@ -427,6 +427,7 @@
{{if .CanDebug}}
<a id="model-image-{{.Cloudbrain.ID}}"
class='imageBtn ui basic {{if ne .Status "RUNNING"}}disabled {{else}}blue {{end}}button'
target="_blank"
href="{{$.RepoLink}}/cloudbrain/{{.Cloudbrain.ID}}/commit_image">{{$.i18n.Tr "repo.submit_image"}}</a>
{{else}}
<a


+ 67
- 130
templates/repo/grampus/trainjob/gpu/new.tmpl View File

@@ -80,8 +80,11 @@
<form 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="">
<input type="hidden" id="ai_engine_name" name="engine_name" value="">
<input type="hidden" id="ai_flavor_name" name="flavor_name" value="">
<input type="hidden" id="ai_image_name" value="{{.image}}">
<input type="hidden" id="fail_dataset_name" value="{{$.dataset_name}}">
<input type="hidden" id="fail_dataset_uuid" value="{{$.attachment}}">
<h4 class="train-job-title ui header ">{{.i18n.Tr "repo.modelarts.train_job.basic_info"}}:</h4>
<div class="required min_title inline field">
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "cloudbrain.resource_cluster"}}</label>
@@ -117,13 +120,17 @@
</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>
<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="64">
<span class="tooltips" style="margin-left: 11.5rem;display: block;">{{.i18n.Tr "cloudbrain.job_name_rule"}}</span>
<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="min_title inline field">
<label class="label-fix-width" style="font-weight: normal;" for="description">{{.i18n.Tr "repo.modelarts.train_job.description"}}</label>
{{if .description}}
<textarea style="width: 80%;" id="description" name="description" rows="3" maxlength="255" placeholder={{.i18n.Tr "repo.modelarts.train_job.new_place"}}>{{.description}}</textarea>
{{else}}
<textarea style="width: 80%;" id="description" name="description" rows="3" maxlength="255" placeholder={{.i18n.Tr "repo.modelarts.train_job.new_place"}} onchange="this.value=this.value.substring(0, 255)" onkeydown="this.value=this.value.substring(0, 255)" onkeyup="this.value=this.value.substring(0, 255)"></textarea>
{{end}}
</div>
<div class="ui divider"></div>

@@ -156,8 +163,8 @@

<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}}
<input style="width: 48.5%;" name="boot_file" id="trainjob_boot_file" value="{{.bootFile}}" tabindex="3" autofocus required maxlength="255" >
{{if .boot_file}}
<input style="width: 48.5%;" name="boot_file" id="trainjob_boot_file" value="{{.boot_file}}" tabindex="3" autofocus required maxlength="255" >
{{else}}
<input style="width: 48.5%;" name="boot_file" id="trainjob_boot_file" value="" tabindex="3" autofocus required maxlength="255" >
{{end}}
@@ -174,33 +181,29 @@
<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>
<input id="store_run_para" type="hidden" name="run_para_list">
<div class="dynamic field" style="margin-top: 1rem;">
{{if .params}}
{{if ne 0 (len .params)}}
{{range $k ,$v := .params}}
<div class="two fields width85" id="para{{$k}}">
<div class="field">
<input type="text" name="shipping_first-name" value={{$v.Label}} required>
</div>
<div class="field">
<input type="text" name="shipping_last-name" value={{$v.Value}} required>
</div>
<span>
<i class="trash icon"></i>
</span>

</div>
{{end}}
{{end}}
{{end}}
<div class="dynamic field" style="margin-top: 1rem;" data-params="{{.run_para_list}}">
</div>
</div>

<div class="required min_title inline field" id="flavor_name">
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.standard"}}</label>
<select class="ui dropdown width81" id="trainjob-flavor" style='width:385px' name="flavor">
{{range .flavor_infos}}
{{if .flavor}}
{{range .flavor_infos}}
{{if eq $.flavor .ID}}
<option value="{{.ID}}">{{.Name}}</option>
{{end}}
{{end}}
{{range .flavor_infos}}
{{if ne $.flavor .ID}}
<option value="{{.ID}}">{{.Name}}</option>
{{end}}
{{end}}
{{else}}
{{range .flavor_infos}}
<option name="flavor" value="{{.ID}}">{{.Name}}</option>
{{end}}
{{end}}
</select>
</div>
@@ -230,125 +233,58 @@
$('.menu .item')
.tab();

let sever_num = $('#trainjob_work_server_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)
}
$(document).ready(function(){
let params = $('.dynamic.field').data('params')
params&&params.parameter.forEach((item,index)=>{
Add_parameter(index,flag=true,item)
})
})
// 参数增加、删除、修改、保存
function Add_parameter(i){
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"}}> ' +
'</div> ' +
'<div class="field"> ' +
'<input type="text" name="shipping_last-name" required placeholder={{.i18n.Tr "repo.modelarts.train_job.parameter_value"}}>' +
'</div>'+
'<span>' +
'<i class="trash icon">' +
'</i>' +
'</span>' +
'</div>'
function Add_parameter(i,flag=false,paramsObject={}) {
let value = ''
value += `<div class="two fields width85" id= "para${i}">`
value += '<div class="field">'
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 += '</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 += '</div>'
value += '<span><i class="trash icon"></i></span>'
value += '</div>'
$(".dynamic.field").append(value)
}

$('#add_run_para').click(function(){
}

$('#add_run_para').click(function () {
var len = $(".dynamic.field .two.fields").length
Add_parameter(len)
});

$(".dynamic.field").on("click",".trash.icon", function() {
$(".dynamic.field").on("click", ".trash.icon", function () {
var index = $(this).parent().parent().index()
$(this).parent().parent().remove()
var len = $(".dynamic.field .two.fields").length
$(".dynamic.field .two.fields").each(function(){
$(".dynamic.field .two.fields").each(function () {
var cur_index = $(this).index()
$(this).attr('id', 'para' + cur_index)
})
});

$('.ui.parameter.green.button').click(function(){
var parameters = [];
$('table tr').each(function() {
$(this).find('td:eq(1)').each(function(){
parameters.push($(this).text());
})
$(this).find('input').each(function(){
parameters.push($(this).text())
})
});
$('.ui.parameter.modal')
.modal('hide');
for(var i = 2; i < parameters.length; i++){
switch(i) {
// 数据集uuid待完成
// case (2):
// console.log(1)
// break;
// $("#trainjob_datasets").val(parameters[i]);
// console.log($("#trainjob_datasets").val())
case (3):
$("input[name='boot_file']").val(parameters[i]);
break;
case (4):
var para = parameters[i].split(" ")
for(var j = 0; j < para.length; j++){
var para_name = para[j].split('=')[0]
var para_value = para[j].split('=')[1]
var len = $(".dynamic.field .two.fields").length
Add_parameter(len)
var pid = 'para' + len
$(".dynamic.field"+ " #" + pid + "").find("input[name=shipping_first-name]").val(para_name)
$(".dynamic.field"+ " #" + pid + "").find("input[name=shipping_last-name]").val(para_value)
}
break;
// 数据集pool_id待完成
// case (5):
// $("select[name='pool_id']").val(parameters[i]);
// break;
case (6):
$("input[name='work_server_number']").val(parameters[i]);
break;
}
}
})

$('.ui.save.checkbox').click(function(){
$(this).checkbox({
onChange: function(){
if ($('.ui.save.checkbox').checkbox('is checked')){
$('#save_para').removeClass("disabled")
}else{
$('#save_para').addClass("disabled")
}
}
});
})

$('.question.circle.icon').hover(function(){
$(this).popup('show')
});

$(".item.active.parameter_config").click(function(){
$('.ui.parameter.modal')
.modal('setting', 'closable', false)
.modal('show');
})

$('.ui.deny.button').click(function(){
$('.ui.parameter.modal')
.modal('hide');
})
$('select.dropdown')
.dropdown();

@@ -369,7 +305,7 @@
identifier : 'display_job_name',
rules: [
{
type: 'regExp[/^[a-zA-Z0-9-_]{1,64}[a-zA-Z0-9_]$/]',
type: 'regExp[/^[a-z0-9][a-z0-9-_]{1,34}[a-z0-9-]$/]',
}
]
},
@@ -414,13 +350,13 @@
document.getElementById("mask").style.display = "none"
}
}
function send_run_para(){
function send_run_para() {
var run_parameters = []
var msg = {}
$(".dynamic.field .two.fields").each(function(){
var para_name = $(this).find('input[name=shipping_first-name]').val()
var para_value = $(this).find('input[name=shipping_last-name]').val()
run_parameters.push({"label": para_name, "value": para_value})
$(".dynamic.field .two.fields").each(function () {
var para_name = $(this).find('input.shipping_first-name').val()
var para_value = $(this).find('input.shipping_last-name').val()
run_parameters.push({ "label": para_name, "value": para_value })
})
msg["parameter"] = run_parameters
msg = JSON.stringify(msg)
@@ -433,9 +369,10 @@
$("input#ai_flavor_name").val(name2)

}
validate();
$('.ui.create_train_job.green.button').click(function(e) {
get_name()
send_run_para()
validate()
validate();
})
</script>

+ 81
- 116
templates/repo/grampus/trainjob/npu/new.tmpl View File

@@ -77,6 +77,8 @@
<input type="hidden" name="action" value="update">
<input type="hidden" id="ai_engine_name" name="engine_name" value="">
<input type="hidden" id="ai_flavor_name" name="flavor_name" value="">
<input type="hidden" id="fail_dataset_name" value="{{$.dataset_name}}">
<input type="hidden" id="fail_dataset_uuid" value="{{$.attachment}}">
<h4 class="train-job-title ui header ">{{.i18n.Tr "repo.modelarts.train_job.basic_info"}}:</h4>
<div class="required min_title inline field">
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "cloudbrain.resource_cluster"}}</label>
@@ -113,13 +115,17 @@
<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>
<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="64">
<span class="tooltips" style="display: block;margin-left: 11.5rem;">{{.i18n.Tr "cloudbrain.job_name_rule"}}</span>
<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="display: block;margin-left: 11.5rem;">{{.i18n.Tr "repo.cloudbrain_jobname_err"}}</span>
</div>

<div class="min_title inline field">
<label class="label-fix-width" style="font-weight: normal;" for="description">{{.i18n.Tr "repo.modelarts.train_job.description"}}</label>
{{if .description}}
<textarea style="width: 80%;" id="description" name="description" rows="3" maxlength="255" placeholder={{.i18n.Tr "repo.modelarts.train_job.new_place"}}>{{.description}}</textarea>
{{else}}
<textarea style="width: 80%;" id="description" name="description" rows="3" maxlength="255" placeholder={{.i18n.Tr "repo.modelarts.train_job.new_place"}} onchange="this.value=this.value.substring(0, 255)" onkeydown="this.value=this.value.substring(0, 255)" onkeyup="this.value=this.value.substring(0, 255)"></textarea>
{{end}}
</div>
<div class="ui divider"></div>

@@ -146,20 +152,32 @@
{{end}}
</select>
</div>

<div class="required min_title inline field" id="engine_name">
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "cloudbrain.mirror"}}</label>
<select class="ui dropdown width81" id="trainjob_images" name="image_id">
{{range .images}}
<option name="image_id" value="{{.ID}}">{{.Name}}</option>
{{if .image_id}}
{{range .images}}
{{if eq $.image_id .ID}}
<option value="{{.ID}}">{{.Name}}</option>
{{end}}
{{end}}
{{range .images}}
{{if ne $.image_id .ID}}
<option value="{{.ID}}">{{.Name}}</option>
{{end}}
{{end}}
{{else}}
{{range .images}}
<option name="image_id" value="{{.ID}}">{{.Name}}</option>
{{end}}
{{end}}
</select>
</div>

<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}}
<input style="width: 48.5%;" name="boot_file" id="trainjob_boot_file" value="{{.bootFile}}" tabindex="3" autofocus required maxlength="255" >
{{if .boot_file}}
<input style="width: 48.5%;" name="boot_file" id="trainjob_boot_file" value="{{.boot_file}}" tabindex="3" autofocus required maxlength="255" >
{{else}}
<input style="width: 48.5%;" name="boot_file" id="trainjob_boot_file" value="" tabindex="3" autofocus required maxlength="255" >
{{end}}
@@ -175,15 +193,29 @@
<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>
<input id="store_run_para" type="hidden" name="run_para_list">
<div class="dynamic field" style="margin-top: 1rem;">
<div class="dynamic field" style="margin-top: 1rem;" data-params="{{.run_para_list}}">
</div>
</div>

<div class="required min_title inline field" id="flavor_name">
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.standard"}}</label>
<select class="ui dropdown width81" id="trainjob-flavor" style='width:385px' name="flavor">
{{range .flavor_infos}}
{{if .flavor}}
{{range .flavor_infos}}
{{if eq $.flavor .ID}}
<option value="{{.ID}}">{{.Name}}</option>
{{end}}
{{end}}
{{range .flavor_infos}}
{{if ne $.flavor .ID}}
<option value="{{.ID}}">{{.Name}}</option>
{{end}}
{{end}}
{{else}}
{{range .flavor_infos}}
<option name="flavor" value="{{.ID}}">{{.Name}}</option>
{{end}}
{{end}}
</select>
</div>
@@ -226,126 +258,58 @@
$('.menu .item')
.tab();

// 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)
// }
// })
$(document).ready(function(){
let params = $('.dynamic.field').data('params')
params&&params.parameter.forEach((item,index)=>{
Add_parameter(index,flag=true,item)
})
})
// 参数增加、删除、修改、保存
function Add_parameter(i){
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"}}> ' +
'</div> ' +
'<div class="field"> ' +
'<input type="text" name="shipping_last-name" required placeholder={{.i18n.Tr "repo.modelarts.train_job.parameter_value"}}>' +
'</div>'+
'<span>' +
'<i class="trash icon">' +
'</i>' +
'</span>' +
'</div>'
function Add_parameter(i,flag=false,paramsObject={}) {
let value = ''
value += `<div class="two fields width85" id= "para${i}">`
value += '<div class="field">'
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 += '</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 += '</div>'
value += '<span><i class="trash icon"></i></span>'
value += '</div>'
$(".dynamic.field").append(value)

}

$('#add_run_para').click(function(){
$('#add_run_para').click(function () {
var len = $(".dynamic.field .two.fields").length
Add_parameter(len)
});

$(".dynamic.field").on("click",".trash.icon", function() {
$(".dynamic.field").on("click", ".trash.icon", function () {
var index = $(this).parent().parent().index()
$(this).parent().parent().remove()
var len = $(".dynamic.field .two.fields").length
$(".dynamic.field .two.fields").each(function(){
$(".dynamic.field .two.fields").each(function () {
var cur_index = $(this).index()
$(this).attr('id', 'para' + cur_index)
})
});

$('.ui.parameter.green.button').click(function(){
var parameters = [];
$('table tr').each(function() {
$(this).find('td:eq(1)').each(function(){
parameters.push($(this).text());
})
$(this).find('input').each(function(){
parameters.push($(this).text())
})

});
$('.ui.parameter.modal')
.modal('hide');
for(var i = 2; i < parameters.length; i++){
switch(i) {
// 数据集uuid待完成
// case (2):
// console.log(1)
// break;
// $("#trainjob_datasets").val(parameters[i]);
// console.log($("#trainjob_datasets").val())
case (3):
$("input[name='boot_file']").val(parameters[i]);
break;
case (4):
var para = parameters[i].split(" ")
for(var j = 0; j < para.length; j++){
var para_name = para[j].split('=')[0]
var para_value = para[j].split('=')[1]
var len = $(".dynamic.field .two.fields").length
Add_parameter(len)
var pid = 'para' + len
$(".dynamic.field"+ " #" + pid + "").find("input[name=shipping_first-name]").val(para_name)
$(".dynamic.field"+ " #" + pid + "").find("input[name=shipping_last-name]").val(para_value)
}
break;
// 数据集pool_id待完成
// case (5):
// $("select[name='pool_id']").val(parameters[i]);
// break;
case (6):
// $("input[name='work_server_number']").val(parameters[i]);
break;
}
}
})

$('.ui.save.checkbox').click(function(){
$(this).checkbox({
onChange: function(){
if ($('.ui.save.checkbox').checkbox('is checked')){
$('#save_para').removeClass("disabled")

}else{
$('#save_para').addClass("disabled")
}
}
});
})

$('.question.circle.icon').hover(function(){
$(this).popup('show')
});

$(".item.active.parameter_config").click(function(){
$('.ui.parameter.modal')
.modal('setting', 'closable', false)
.modal('show');
})

$('.ui.deny.button').click(function(){
$('.ui.parameter.modal')
.modal('hide');
})
$('select.dropdown')
.dropdown();

@@ -366,7 +330,7 @@
identifier : 'display_job_name',
rules: [
{
type: 'regExp[/^[a-zA-Z0-9-_]{1,64}[a-zA-Z0-9_]$/]',
type: 'regExp[/^[a-z0-9][a-z0-9-_]{1,34}[a-z0-9-]$/]',
}
]
},
@@ -402,13 +366,13 @@
document.getElementById("mask").style.display = "none"
}
}
function send_run_para(){
function send_run_para() {
var run_parameters = []
var msg = {}
$(".dynamic.field .two.fields").each(function(){
var para_name = $(this).find('input[name=shipping_first-name]').val()
var para_value = $(this).find('input[name=shipping_last-name]').val()
run_parameters.push({"label": para_name, "value": para_value})
$(".dynamic.field .two.fields").each(function () {
var para_name = $(this).find('input.shipping_first-name').val()
var para_value = $(this).find('input.shipping_last-name').val()
run_parameters.push({ "label": para_name, "value": para_value })
})
msg["parameter"] = run_parameters
msg = JSON.stringify(msg)
@@ -425,9 +389,10 @@
$("input#trainjob_work_server_num").val(val_server_num_select)

}
validate();
$('.ui.create_train_job.green.button').click(function(e) {
get_name()
send_run_para()
validate()
validate();
})
</script>

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

@@ -190,7 +190,6 @@
<script src="{{StaticUrlPrefix}}/self/js/notebook/katex.min.js"></script>
<script src="{{StaticUrlPrefix}}/self/js/notebook/katex-auto-render.min.js"></script>
<script src="{{StaticUrlPrefix}}/self/js/notebook/notebook.min.js"></script>
<script src="{{StaticUrlPrefix}}/self/js/notebook/notebook.min.js"></script>
<link rel="stylesheet" href="{{StaticUrlPrefix}}/self/css/notebook/katex.min.css" />
<link rel="stylesheet" href="{{StaticUrlPrefix}}/self/css/notebook/prism.css" />
<link rel="stylesheet" href="{{StaticUrlPrefix}}/self/css/notebook/notebook.css" />

+ 2
- 2
templates/repo/migrate.tmpl View File

@@ -11,7 +11,7 @@
{{template "base/alert" .}}
<div class="inline required field {{if .Err_CloneAddr}}error{{end}}">
<label for="clone_addr">{{.i18n.Tr "repo.migrate.clone_address"}}</label>
<input id="clone_addr" name="clone_addr" value="{{.clone_addr}}" autofocus required>
<input id="clone_addr" name="clone_addr" value="{{.clone_addr}}" autofocus required autocomplete="off" />
<span class="help">
{{.i18n.Tr "repo.migrate.clone_address_desc"}}{{if .ContextUser.CanImportLocal}} {{.i18n.Tr "repo.migrate.clone_local_path"}}{{end}}
<br/>{{.i18n.Tr "repo.migrate.migrate_items_options"}}
@@ -102,7 +102,7 @@
<button class="ui green button" id="submit_reponame">
{{.i18n.Tr "repo.migrate_repo"}}
</button>
<a class="ui button" href="{{AppSubUrl}}/">{{.i18n.Tr "cancel"}}</a>
<a class="ui button" href="javascript:history.go(-1)">{{.i18n.Tr "cancel"}}</a>
</div>
</div>
</form>


+ 88
- 57
templates/repo/modelarts/inferencejob/new.tmpl View File

@@ -58,16 +58,16 @@
<input type="hidden" name="action" value="update">
<input type="hidden" id="ai_engine_name" name="engine_names" value="">
<input type="hidden" id="ai_flaver_name" name="flaver_names" value="">
{{if $.model_version}}
<input type="hidden" id="ai_model_version" name="model_version" value="{{$.model_version}}">
{{else}}
<input type="hidden" id="ai_model_version" name="model_version" value="">
{{end}}
{{if $.label_names}}
<input type="hidden" id="ai_model_label" name="label_names" value="{{$.label_names}}">
{{else}}
<input type="hidden" id="ai_model_label" name="label_names" value="">
{{end}}

<input type="hidden" id="failed_train_url" value="{{$.train_url}}">
<input type="hidden" id="failed_model_name" value="{{$.model_name}}">
<input type="hidden" id="failed_model_version" value="{{$.model_version}}">
<input type="hidden" id="failed_ckpt_name" value="{{$.ckpt_name}}">
<input type="hidden" id="failed_train_url" value="{{$.train_url}}">
<input type="hidden" id="fail_dataset_name" value="{{$.dataset_name}}">
<input type="hidden" id="fail_dataset_uuid" value="{{$.attachment}}">

<h4 class="unite title ui header ">{{.i18n.Tr "repo.modelarts.train_job.basic_info"}}:</h4>
<div class="required min_title inline field">
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "cloudbrain.compute_resource"}}</label>
@@ -94,29 +94,27 @@
</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>
<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}}" onkeyup="this.value=this.value.replace(/[, ]/g,'')" tabindex="3" autofocus required maxlength="64">
<span class="tooltips" style="margin-left:11.5rem;display: block;">{{.i18n.Tr "cloudbrain.job_name_rule"}}</span>
<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}}" onkeyup="this.value=this.value.replace(/[, ]/g,'')" tabindex="3" autofocus required maxlength="36">
<span class="tooltips" style="margin-left:11.5rem;display: block;">{{.i18n.Tr "repo.cloudbrain_jobname_err"}}</span>
</div>

<div class="min_title inline field">
<label class="label-fix-width" style="font-weight: normal;" for="description">{{.i18n.Tr "repo.modelarts.train_job.description"}}</label>&nbsp;&nbsp;
<label class="label-fix-width" style="font-weight: normal;" for="description">{{.i18n.Tr "repo.modelarts.train_job.description"}}</label>
{{if .description}}
<textarea style="width: 80%;" id="description" name="description" rows="3" maxlength="255" placeholder={{.i18n.Tr "repo.modelarts.train_job.new_place"}}>{{.description}}</textarea>
{{else}}
<textarea style="width: 80%;" id="description" name="description" rows="3" maxlength="255" placeholder={{.i18n.Tr "repo.modelarts.train_job.new_place"}} onchange="this.value=this.value.substring(0, 255)" onkeydown="this.value=this.value.substring(0, 255)" onkeyup="this.value=this.value.substring(0, 255)"></textarea>
{{end}}
</div>
<div class="ui divider"></div>

<!-- 模型相关配置 -->
<h4 class="unite title ui header ">{{.i18n.Tr "repo.modelarts.train_job.parameter_setting"}}:</h4>
<div class="required unite inline min_title fields" style="width: 96.8%;">
<div class="required eight wide field">
<label style="font-weight: normal;white-space: nowrap;width: 210px;text-align: right;">{{.i18n.Tr "repo.modelarts.infer_job.select_model"}}</label>
<div class="ui fluid search selection dropdown loading " id="select_model">
{{if $.ckpt_name}}
<input type="hidden" name="model_name" value="{{$.model_name}}" required>
<div class="text">{{$.model_name}}</div>
{{else}}
<input type="hidden" name="model_name" required>
<div class="text"></div>
{{end}}
<i class="dropdown icon"></i>
<div class="menu" id="model_name">
</div>
@@ -124,13 +122,8 @@
</div>
<div class="three wide field">
<div class="ui fluid search selection dropdown" id="select_model_version">
{{if $.ckpt_name}}
<input type="hidden" name="train_url" value="{{$.train_url}}" required>
<div class="text">{{$.model_version}}</div>
{{else}}
<input type="hidden" name="train_url" required>
<div class="text"></div>
{{end}}
<i class="dropdown icon"></i>
<div class="menu" id="model_name_version">
</div>
@@ -139,13 +132,8 @@
</div>
<div class="five wide field">
<div class="ui fluid search selection dropdown" id="select_model_checkpoint">
{{if $.ckpt_name}}
<input type="hidden" name="ckpt_name" value="{{$.ckpt_name}}" required>
<div class="text">{{$.ckpt_name}}</div>
{{else}}
<input type="hidden" name="ckpt_name" required>
<div class="text"></div>
{{end}}
<i class="dropdown icon"></i>
<div class="menu" id="model_checkpoint">
</div>
@@ -169,9 +157,22 @@

<div class="field" style="flex: 2;" id="engine_name">
<select class="ui dropdown width" id="trainjob_engine_versions" name="engine_id">
{{if .engine_id}}
{{range .engine_versions}}
<option name="engine_id" value="{{.ID}}">{{.Value}}</option>
{{if eq $.engine_id .ID}}
<option value="{{.ID}}">{{.Value}}</option>
{{end}}
{{end}}
{{range .engine_versions}}
{{if ne $.engine_id .ID}}
<option value="{{.ID}}">{{.Value}}</option>
{{end}}
{{end}}
{{else}}
{{range .engine_versions}}
<option value="{{.ID}}">{{.Value}}</option>
{{end}}
{{end}}
</select>

</div>
@@ -251,8 +252,21 @@
<div class="required min_title inline field" id="flaver_name">
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.standard"}}</label>
<select class="ui dropdown width80" id="trainjob-flavor" name="flavor">
{{range .flavor_infos}}
{{if .flavor}}
{{range .flavor_infos}}
{{if eq $.flavor .Code}}
<option value="{{.Code}}">{{.Value}}</option>
{{end}}
{{end}}
{{range .flavor_infos}}
{{if ne $.flavor .Code}}
<option value="{{.Code}}">{{.Value}}</option>
{{end}}
{{end}}
{{else}}
{{range .flavor_infos}}
<option name="flavor" value="{{.Code}}">{{.Value}}</option>
{{end}}
{{end}}
</select>
</div>
@@ -286,30 +300,38 @@
let nameMap,nameList
$(".ui.button").attr('href',url_href)
// 获取模型列表和模型名称对应的模型版本
$.get(`${RepoLink}/modelmanage/query_model_for_predict?type=1`, (data) => {
$(document).ready(function(){
modelVersion()
modelCkpt()
nameMap = data.nameMap
nameList = data.nameList
let html = ''
nameList.forEach(element => {
html += `<div class="item" data-value=${element}>${element}</div>`
});
if(nameList.length!==0){
const initModelVersion = nameMap[nameList[0]][0]
const initTrainTaskInfo = JSON.parse(initModelVersion.TrainTaskInfo)
$('#model_name').append(html)
$("#select_model").dropdown('set text',nameList[0])
$("#select_model").dropdown('set value',nameList[0],nameList[0])
}

$('#select_model').removeClass("loading")
$.get(`${RepoLink}/modelmanage/query_model_for_predict?type=1`, (data) => {
nameMap = data.nameMap
nameList = data.nameList
let faildModelName = document.getElementById('failed_model_name').value
let html = ''
nameList.forEach(element => {
html += `<div class="item" data-value=${element}>${element}</div>`
});
if(nameList.length!==0){
$('#model_name').append(html)
if(faildModelName){
$("#select_model").dropdown('set text',faildModelName)
$("#select_model").dropdown('set value',faildModelName)
}else{
$("#select_model").dropdown('set text',nameList[0])
$("#select_model").dropdown('set value',nameList[0],nameList[0])
}
}
$('#select_model').removeClass("loading")
})
})
// 根据选中的模型名称获取相应的模型版本
function modelVersion(){
let faildModelVersion = $('#failed_model_version').val()
let faildTrainUrl = $('#failed_train_url').val()
$('#select_model').dropdown({
onChange: function(value, text, $selectedItem) {
console.log("-----------------")
$("#select_model_version").addClass("loading")
$('#model_name_version').empty()
let html = ''
@@ -322,13 +344,20 @@
$("#select_model_version").removeClass("loading")
const initVersionText = $('#model_name_version div.item:first-child').text()
const initVersionValue = $('#model_name_version div.item:first-child').data('value')
$("#select_model_version").dropdown('set text',initVersionText)
$("#select_model_version").dropdown('set value',initVersionValue,initVersionText,$('#model_name_version div.item:first-child'))
if(faildModelVersion&&faildTrainUrl){
$("#select_model_version").dropdown('set text',faildModelVersion)
$("#select_model_version").dropdown('set value',faildTrainUrl,faildModelVersion,$('#model_name_version div.item:first-child'))
}else{
$("#select_model_version").dropdown('set text',initVersionText)
$("#select_model_version").dropdown('set value',initVersionValue,initVersionText,$('#model_name_version div.item:first-child'))
}
}
})
}
// 根据选中的模型版本获取相应的模型权重文件
function modelCkpt(){
let faildCkptName = $('#failed_ckpt_name').val()
$('#select_model_version').dropdown({
onChange: function(value, text, $selectedItem) {
const dataID = $selectedItem[0].getAttribute("data-id")
@@ -343,17 +372,19 @@
if(!element.IsDir && loadCheckpointFile.includes(ckptSuffix[ckptSuffix.length-1])){
html += `<div class="item" data-value=${element.FileName}>${element.FileName}</div>`
}

})
$('#model_checkpoint').append(html)
$("#select_model_checkpoint").removeClass("loading")
const initVersionText = $('#model_checkpoint div.item:first-child').text()
const initVersionValue = $('#model_checkpoint div.item:first-child').data('value')
$("#select_model_checkpoint").dropdown('set text',initVersionText)
$("#select_model_checkpoint").dropdown('set value',initVersionValue,initVersionText,$('#model_name_version div.item:first-child'))
if(faildCkptName){
$("#select_model_checkpoint").dropdown('set text',faildCkptName)
$("#select_model_checkpoint").dropdown('set value',faildCkptName,faildCkptName,$('#model_name_version div.item:first-child'))
}else{
$("#select_model_checkpoint").dropdown('set text',initVersionText)
$("#select_model_checkpoint").dropdown('set value',initVersionValue,initVersionText,$('#model_name_version div.item:first-child'))
}
})


$("input#ai_model_version").val(text)
$("input#ai_model_label").val(label)
}
@@ -419,7 +450,6 @@
let name2=$("#flaver_name .text").text()
$("input#ai_engine_name").val(name1)
$("input#ai_flaver_name").val(name2)

}
function validate(){
$('.ui.form')
@@ -438,7 +468,7 @@
identifier : 'display_job_name',
rules: [
{
type: 'regExp[/^[a-zA-Z0-9-_]{1,64}[^-]$/]',
type: 'regExp[/^[a-z0-9][a-z0-9-_]{1,34}[a-z0-9-]$/]',
}
]
},
@@ -489,9 +519,10 @@
document.getElementById("mask").style.display = "none"
}
}
validate();
$('.ui.create_train_job.green.button').click(function(e) {
send_run_para()
get_name()
validate()
validate();
})
</script>

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

@@ -50,7 +50,7 @@
</div>
<div class="inline required field">
<label>{{.i18n.Tr "cloudbrain.task_name"}}</label>
<input name="display_job_name" id="cloudbrain_job_name" placeholder="任务名称" value="{{.display_job_name}}" tabindex="3" autofocus required maxlength="255" onkeyup="this.value=this.value.replace(/[, ]/g,'')">
<input name="display_job_name" id="cloudbrain_job_name" placeholder="任务名称" value="{{.display_job_name}}" tabindex="3" autofocus required maxlength="36" onkeyup="this.value=this.value.replace(/[, ]/g,'')">
</div>

<div class="inline required field">
@@ -110,15 +110,37 @@

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

function validate(){
$('.ui.form').form({
on: 'blur',
fields: {
display_job_name:{
identifier : 'display_job_name',
rules: [
{
type: 'regExp[/^[a-z0-9][a-z0-9-_]{1,34}[a-z0-9-]$/]',
}
]
},
},
onSuccess: function(){
},
onFailure: function(e){
return false;
}
})
}
validate();

form.onsubmit = function(e){
let value_task = $("input[name='display_job_name']").val()


let re = /^[a-z0-9][a-z0-9-_]{1,36}$/
let re = /^[a-z0-9][a-z0-9-_]{1,34}[a-z0-9-]$/
let flag = re.test(value_task)
if(!flag){
$('#messageInfo').css('display','block')
let str = '只能以小写字母或数字开头且只包含小写字母、数字、_和-、最长36个字符。'
let str = '只能以小写字母或数字开头且只包含小写字母、数字、_和-,不能以_结尾,最长36个字符。'
$('#messageInfo p').text(str)
return false
}


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

@@ -257,7 +257,9 @@
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 class="redo icon redo-color"></i>
</span>
</div>
</span>
</span>
@@ -357,7 +359,15 @@

<td class="ti-text-form-content">
<div class="text-span text-span-w" id="{{.VersionName}}-mirror">
{{.Image}}
<span class="ui poping up clipboard" data-position="top center" id="clipboard-btn" style="cursor:pointer"
data-clipboard-text="{{.Image}}"
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"
>
<span title="{{.Image}}">{{.Image}}</span>
</span>
</div>
</td>
</tr>


+ 39
- 10
templates/repo/modelarts/trainjob/new.tmpl View File

@@ -122,13 +122,17 @@
</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="64">
<span class="tooltips" style="margin-left:11.5rem;display: block;">{{.i18n.Tr "cloudbrain.job_name_rule"}}</span>
<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">
<label class="label-fix-width" style="font-weight: normal;" for="description">{{.i18n.Tr "repo.modelarts.train_job.description"}}</label>
{{if .description}}
<textarea style="width: 80%;" id="description" name="description" rows="3" maxlength="255" placeholder={{.i18n.Tr "repo.modelarts.train_job.new_place"}}>{{.description}}</textarea>
{{else}}
<textarea style="width: 80%;" id="description" name="description" rows="3" maxlength="255" placeholder={{.i18n.Tr "repo.modelarts.train_job.new_place"}} onchange="this.value=this.value.substring(0, 255)" onkeydown="this.value=this.value.substring(0, 255)" onkeyup="this.value=this.value.substring(0, 255)"></textarea>
{{end}}
</div>
<div class="ui divider"></div>

@@ -170,9 +174,22 @@

<div class="field" style="flex: 2;" id="engine_name">
<select class="ui dropdown width" id="trainjob_engine_versions" name="engine_id">
{{if .engine_id}}
{{range .engine_versions}}
<option name="engine_id" value="{{.ID}}">{{.Value}}</option>
{{if eq $.engine_id .ID}}
<option value="{{.ID}}">{{.Value}}</option>
{{end}}
{{end}}
{{range .engine_versions}}
{{if ne $.engine_id .ID}}
<option value="{{.ID}}">{{.Value}}</option>
{{end}}
{{end}}
{{else}}
{{range .engine_versions}}
<option value="{{.ID}}">{{.Value}}</option>
{{end}}
{{end}}
</select>

</div>
@@ -220,7 +237,6 @@
</div>
</div>


<div class="required min_title field " style="display: none;">
<label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.resource_pool"}}</label>
<select class="ui dropdown" id="trainjob_resource_pool" style='width:385px' name="pool_id">
@@ -246,12 +262,24 @@
</div>
</div>
</div>

<div class="required inline min_title field" id="flaver_name">
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.standard"}}</label>
<select class="ui dropdown width48" id="trainjob-flavor" name="flavor">
{{range .flavor_infos}}
<option name="flavor" value="{{.Code}}">{{.Value}}</option>
{{if .flavor}}
{{range .flavor_infos}}
{{if eq $.flavor .Code}}
<option value="{{.Code}}">{{.Value}}</option>
{{end}}
{{end}}
{{range .flavor_infos}}
{{if ne $.flavor .Code}}
<option value="{{.Code}}">{{.Value}}</option>
{{end}}
{{end}}
{{else}}
{{range .flavor_infos}}
<option name="flavor" value="{{.Code}}">{{.Value}}</option>
{{end}}
{{end}}
</select>
</div>
@@ -441,7 +469,7 @@
identifier: 'display_job_name',
rules: [
{
type: 'regExp[/^[a-zA-Z0-9-_]{1,64}[a-zA-Z0-9_]$/]',
type: 'regExp[/^[a-z0-9][a-z0-9-_]{1,34}[a-z0-9-]$/]',
}
]
},
@@ -500,9 +528,10 @@
$("input#trainjob_work_server_num").val(val_server_num_select)

}
validate();
$('.ui.create_train_job.green.button').click(function (e) {
get_name()
send_run_para()
validate()
send_run_para();
validate();
})
</script>

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

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

{{if .CanDel}}
<a class="ti-action-menu-item stop-show-version {{if eq .Status "KILLED" "FAILED" "START_FAILED" "KILLING" "COMPLETED"}}disabled {{end}}"
<a class="ti-action-menu-item stop-show-version {{if eq .Status "KILLED" "FAILED" "START_FAILED" "KILLING" "COMPLETED" "SUCCEEDED" "STOPPED"}}disabled {{end}}"
id="{{.VersionName}}-stop"
data-jobid="{{.JobID}}"
data-repopath="{{$.RepoRelPath}}/modelarts/train-job"


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

@@ -6,7 +6,8 @@
text-align: right;
}
.inline .ui.dropdown .text {
color: rgba(0, 0, 0, .87) !important
color: rgba(0, 0, 0, .87) !important;
max-width: 360px;
}
.newtext{
left: 15px !important


+ 10
- 4
templates/repo/view_file.tmpl View File

@@ -103,20 +103,23 @@
{{end}}
</div>
{{else if .FileSize}}
<table>
{{if .IsNoteBook}}
<div id="notebook"></div>

{{else}}
<table>
<tbody>
<tr>
{{if .IsFileTooLarge}}
<td><strong>{{.i18n.Tr "repo.file_too_large"}}</strong></td>
{{else if .IsNoteBook}}
<td id="notebook"></td>
{{else}}
<td class="lines-num">{{.LineNums}}</td>
<td class="lines-code"><pre><code class="{{.HighlightClass}}"><ol class="linenums">{{.FileContent}}</ol></code></pre></td>
{{end}}
</tr>
</tbody>
</table>
</table>
{{end}}
{{end}}
</div>
</div>
@@ -134,6 +137,9 @@ function showNoteBook(){
var isNoteBook = {{.IsNoteBook}}
if (isNoteBook) {
var jsonStr = "{{.FileContent}}"
nb.markdown.setOptions({
baseUrl: {{.FileParentURL}}
});
var notebook = nb.parse(JSON.parse(jsonStr));
var rendered = notebook.render();
$("#notebook").append(rendered);


+ 84
- 41
templates/user/dashboard/cloudbrains.tmpl View File

@@ -20,7 +20,7 @@
data-all-compute="{{.i18n.Tr "admin.cloudbrain.all_computing_resources"}}"
data-all-status="{{.i18n.Tr "admin.cloudbrain.all_status"}}"></div>
{{template "admin/cloudbrain/search_dashboard" .}}
<div class="ui container" style="width: 80%;">
<div class="ui container" style="width: 90%;">
{{template "base/alert" .}}
<div class="ui grid">
<div class="row">
@@ -30,30 +30,42 @@
<!-- 表头 -->
<div class="ui grid stackable" style="background: #f0f0f0;;">
<div class="row">
<div class="three wide column nowrap" style="width:15%">
<span style="margin:0 6px">{{$.i18n.Tr "repo.cloudbrain_task"}}</span>
<div class="three wide column nowrap" style="width:12%!important">
<span>{{$.i18n.Tr "repo.cloudbrain_task"}}</span>
</div>
<div class="two wide column text center nowrap" style="width: 11% !important;">
<!-- 集群 -->
<div class="one wide column text center nowrap" style="width:8% !important;">
<span>{{$.i18n.Tr "repo.modelarts.cluster"}}</span>
</div>
<div class="two wide column text center nowrap" style="width: 8% !important;">
<span>{{$.i18n.Tr "repo.modelarts.status"}}</span>
</div>
<div class="one wide column text center nowrap" style="width:10%">
<span style="margin:0 6px">{{$.i18n.Tr "repo.cloudbrain_task_type"}}</span>
<div class="one wide column text center nowrap" style="width:8% !important">
<span>{{$.i18n.Tr "repo.cloudbrain_task_type"}}</span>
</div>
<div class="two wide column text center nowrap" style="width: 11% !important;">
<div class="two wide column text center nowrap" style="width: 8% !important;">
<span>{{$.i18n.Tr "repo.modelarts.createtime"}}</span>
</div>
<div class="one wide column text center nowrap" style="width:8.5% !important;">
<div class="one wide column text center nowrap" style="width:6% !important;">
<span>{{$.i18n.Tr "repo.cloudbrain_status_runtime"}}</span>
</div>
<div class="one wide column text center nowrap" style="width:8.5% !important;">
<div class="one wide column text center nowrap" style="width:6% !important;">
<span>{{$.i18n.Tr "repo.modelarts.computing_resources"}}</span>
</div>

<div class="two wide column text center nowrap" style="width: 14.5%!important;">
<!-- 智算中心 -->
<div class="one wide column text center nowrap" style="width:8% !important;">
<span>{{$.i18n.Tr "repo.modelarts.ai_center"}}</span>
</div>
<!-- XPU类型 -->
<div class="one wide column text center nowrap" style="width:10% !important;">
<span>{{$.i18n.Tr "repo.modelarts.card_type"}}</span>
</div>
<div class="two wide column text center nowrap" style="width: 11%!important;">
<span>{{$.i18n.Tr "repository"}}</span>
</div>

<div class="three wide column text center nowrap" style="width: 21.5%!important;">
<div class="three wide column text center nowrap" style="width: 15%!important;">
<span>{{$.i18n.Tr "repo.cloudbrain_operate"}}</span>
</div>
</div>
@@ -70,48 +82,52 @@
{{$JobID = .JobID}}
{{end}}
<!-- {{$JobID}} -->
<div class="three wide column nowrap" style="width:15%">
<div class="three wide column nowrap" style="width:12% !important">
{{if eq .JobType "DEBUG"}}
<a class="title"
href="{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}{{if eq .ComputeResource "CPU/GPU"}}/cloudbrain/{{$JobID}}{{else}}/modelarts/notebook/{{$JobID}}{{end}}"
title="{{.DisplayJobName}}" style="font-size: 14px;">
title="{{.DisplayJobName}}" style="font-size: 14px;padding-right:0px">
<span class="fitted"
style="width: 90%;vertical-align: middle;">{{.DisplayJobName}}</span>
</a>
{{else if or (eq .JobType "SNN4IMAGENET") (eq .JobType "BRAINSCORE")}}
<a class="title"
href="{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}/cloudbrain/benchmark/{{$JobID}}"
title="{{.DisplayJobName}}" style="font-size: 14px;">
title="{{.DisplayJobName}}" style="font-size: 14px;padding-right:0px">
<span class="fitted"
style="width: 90%;vertical-align: middle;">{{.DisplayJobName}}</span>
</a>
{{else if eq .JobType "INFERENCE"}}
<a class="title"
href="{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}/{{if eq .Cloudbrain.Type 1}}modelarts{{else if eq .Cloudbrain.Type 0}}cloudbrain{{end}}/inference-job/{{$JobID}}"
title="{{.DisplayJobName}}" style="font-size: 14px;">
title="{{.DisplayJobName}}" style="font-size: 14px;padding-right:0px">
<span class="fitted"
style="width: 90%;vertical-align: middle;">{{.DisplayJobName}}</span>
</a>
{{else if eq .JobType "TRAIN"}}
<a class="title"
href="{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}/{{if eq .Cloudbrain.Type 1}}modelarts{{else if eq .Cloudbrain.Type 0}}cloudbrain{{else if eq .Cloudbrain.Type 2}}grampus{{end}}/train-job/{{$JobID}}"
title="{{.DisplayJobName}}" style="font-size: 14px;">
title="{{.DisplayJobName}}" style="font-size: 14px;padding-right:0px">
<span class="fitted"
style="width: 90%;vertical-align: middle;">{{.DisplayJobName}}</span>
</a>
{{else if eq .JobType "BENCHMARK"}}
<a class="title"
href="{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}/cloudbrain/benchmark/{{$JobID}}"
title="{{.DisplayJobName}}" style="font-size: 14px;">
title="{{.DisplayJobName}}" style="font-size: 14px;padding-right:0px">
<span class="fitted"
style="width: 90%;vertical-align: middle;">{{.DisplayJobName}}</span>
</a>
{{end}}
</div>

<!-- 集群 -->
<div class="one wide column text center nowrap" style="width:8% !important;">
<span
style="font-size: 12px;">{{if .Cluster}}{{.Cluster}}{{else}}--{{end}}</span>
</div>
<!-- 任务状态 -->
<div class="two wide column text center nowrap"
style="padding-left: 2.2rem !important; width: 11% !important;">
style="width: 8% !important;">
<span class="job-status" id="{{$JobID}}"
data-repopath='{{.Repo.OwnerName}}/{{.Repo.Name}}{{if eq .JobType "DEBUG"}}{{if eq .ComputeResource "CPU/GPU"}}/cloudbrain{{else}}/modelarts/notebook{{end}}{{else if eq .JobType "INFERENCE"}}{{if eq .ComputeResource "CPU/GPU"}}/cloudbrain{{else}}/modelarts{{end}}/inference-job{{else if eq .JobType "TRAIN"}}{{if eq .ComputeResource "NPU"}}/modelarts/train-job{{else}}/cloudbrain/train-job{{end}}{{else if eq .JobType "BENCHMARK"}}/cloudbrain{{end}}'
data-jobid="{{$JobID}}" data-version="{{.VersionName}}">
@@ -123,32 +139,44 @@
<!-- 任务类型 -->

{{$JobType := $.i18n.Tr (printf "cloudbrain.%s" .JobType)}}
<div class="one wide column text center nowrap" style="width:10%">
<div class="one wide column text center nowrap" style="width:8% !important">
<span style="font-size: 12px;" title="{{.JobType}}">{{$JobType}}</span>
</div>
<!-- 任务创建时间 -->
<div class="two wide column text center nowrap" style="width: 11% !important;">
<div class="two wide column text center nowrap" style="width: 8% !important;">
<span style="font-size: 12px;"
class="">{{TimeSinceUnix1 .Cloudbrain.CreatedUnix}}</span>
</div>
<!-- 任务运行时间 -->
<div class="one wide column text center nowrap" style="width:8.5% !important;">
<div class="one wide column text center nowrap" style="width:6% !important;">
<span style="font-size: 12px;"
id="duration-{{$JobID}}">{{if .TrainJobDuration}}{{.TrainJobDuration}}{{else}}--{{end}}</span>
</div>
<!-- 计算资源 -->
<div class="one wide column text center nowrap" style="width:8.5% !important;">
<div class="one wide column text center nowrap" style="width:6% !important;">
<span
style="font-size: 12px;">{{if .ComputeResource}}{{.ComputeResource}}{{else}}--{{end}}</span>
</div>
<!-- 智算中心 -->
<div class="one wide column text center nowrap" style="width:8% !important;">
<span
style="font-size: 12px;">{{if .AiCenter}}{{.AiCenter}}{{else}}--{{end}}</span>
</div>
<!-- XPU类型 -->
<div class="one wide column text center nowrap" style="width:10% !important;">
<span style="font-size: 12px;" title="{{.CardType}}">
{{if .CardType}}{{.CardType}}{{else}}--{{end}}
</span>
</div>

<!-- 项目 -->
<div class="two wide column text center nowrap" style="width: 14.5%!important;">
<div class="two wide column text center nowrap" style="width: 11%!important;">
<a href="{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}"
title="{{.Repo.OwnerName}}/{{.Repo.Alias}}">{{.Repo.OwnerName}}/{{.Repo.Alias}}</a>
</div>

<div class="three wide column text center nowrap" style="width: 21.5%!important;">
<div class="three wide column text center nowrap" style="width: 15%!important;">
{{if eq .JobType "DEBUG"}}
<div class="ui compact buttons">
<form id="debugAgainForm-{{$JobID}}">
@@ -226,33 +254,37 @@
<div class="ui grid stackable item">
<div class="row">
<!-- 任务名 -->
<div class="three wide column nowrap" style="width:15%">
<div class="three wide column nowrap" style="width:12% !important">
{{if eq .JobType "DEBUG"}}
<a class="title" href="" title="{{.DisplayJobName}}" style="font-size: 14px;">
<a class="title" href="" title="{{.DisplayJobName}}" style="font-size: 14px;padding-right:0px">
<span class="fitted"
style="width: 90%;vertical-align: middle;">{{.DisplayJobName}}</span>
</a>
{{else if eq .JobType "INFERENCE"}}
<a class="title" href="" title="{{.DisplayJobName}}" style="font-size: 14px;">
<a class="title" href="" title="{{.DisplayJobName}}" style="font-size: 14px;padding-right:0px">
<span class="fitted"
style="width: 90%;vertical-align: middle;">{{.DisplayJobName}}</span>
</a>
{{else if eq .JobType "TRAIN"}}
<a class="title" href="" title="{{.DisplayJobName}}" style="font-size: 14px;">
<a class="title" href="" title="{{.DisplayJobName}}" style="font-size: 14px;padding-right:0px">
<span class="fitted"
style="width: 90%;vertical-align: middle;">{{.DisplayJobName}}</span>
</a>
{{else if eq .JobType "BENCHMARK"}}
<a class="title" href="" title="{{.DisplayJobName}}" style="font-size: 14px;">
<a class="title" href="" title="{{.DisplayJobName}}" style="font-size: 14px;padding-right:0px">
<span class="fitted"
style="width: 90%;vertical-align: middle;">{{.DisplayJobName}}</span>
</a>
{{end}}
</div>

<!-- 集群 -->
<div class="one wide column text center nowrap" style="width:8% !important;">
<span
style="font-size: 12px;">{{if .Cluster}}{{.Cluster}}{{else}}--{{end}}</span>
</div>
<!-- 任务状态 -->
<div class="two wide column text center nowrap"
style="padding-left: 2.2rem !important; width: 11% !important;">
style="padding-left: 2.2rem !important; width: 8% !important;">
<span class="job-status" id="{{$JobID}}" data-jobid="{{$JobID}}"
data-version="{{.VersionName}}">
<span><i id="{{$JobID}}-icon" style="vertical-align: middle;"
@@ -262,31 +294,42 @@
</div>
<!-- 任务类型 -->
{{$JobType := $.i18n.Tr (printf "cloudbrain.%s" .JobType)}}
<div class="one wide column text center nowrap" style="width:10%">
<div class="one wide column text center nowrap" style="width:8%">
<span style="font-size: 12px;" title="{{.JobType}}">{{$JobType}}</span>
</div>
<!-- 任务创建时间 -->
<div class="two wide column text center nowrap" style="width: 11% !important;">
<div class="two wide column text center nowrap" style="width: 8% !important;">
<span style="font-size: 12px;"
class="">{{TimeSinceUnix1 .Cloudbrain.CreatedUnix}}</span>
</div>
<!-- 任务运行时间 -->
<div class="one wide column text center nowrap" style="width:8.5% !important;">
<div class="one wide column text center nowrap" style="width:6% !important;">
<span style="font-size: 12px;"
id="duration-{{$JobID}}">{{if .TrainJobDuration}}{{.TrainJobDuration}}{{else}}--{{end}}</span>
</div>
<!-- 计算资源 -->
<div class="one wide column text center nowrap" style="width:8.5% !important;">
<div class="one wide column text center nowrap" style="width:6% !important;">
<span
style="font-size: 12px;">{{if .ComputeResource}}{{.ComputeResource}}{{else}}--{{end}}</span>
</div>
<!-- 创建者 -->
<!-- 智算中心 -->
<div class="one wide column text center nowrap" style="width:8% !important;">
<span
style="font-size: 12px;">{{if .AiCenter}}{{.AiCenter}}{{else}}--{{end}}</span>
</div>
<!-- XPU类型 -->
<div class="one wide column text center nowrap" style="width:10% !important;">
<span style="font-size: 12px;" title="{{.CardType}}">
{{if .CardType}}{{.CardType}}{{else}}--{{end}}
</span>
</div>

<!-- 项目 -->
<div class="two wide column text center nowrap" style="width: 14.5%!important;">
<div class="two wide column text center nowrap" style="width: 11%!important;">
<a href="" title="">--</a>
</div>
<div class="three wide column text center nowrap" style="width: 21.5%!important;">
<div class="three wide column text center nowrap" style="width: 15%!important;">
{{if eq .JobType "DEBUG"}}
<div class="ui compact buttons">
<form id="debugAgainForm-{{$JobID}}">
@@ -361,4 +404,4 @@
</div>
</div>
</div>
{{template "base/footer" .}}
{{template "base/footer" .}}

+ 12
- 10
web_src/js/components/Model.vue View File

@@ -6,7 +6,7 @@
ref="table"
:data="tableData"
style="min-width: 100%"
row-key="ID"
row-key="rowKey"
lazy
:load="load"
:tree-props="{children: 'Children', hasChildren: 'hasChildren'}"
@@ -106,7 +106,7 @@
<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)">删除</a>
<a :class="{'disabled':!scope.row.IsCanDelete}" @click="deleteModel(scope.row.ID,scope.row.cName,scope.row.rowKey)">删除</a>
</div>
</template>
@@ -171,6 +171,7 @@ export default {
tableData[i].EngineName = this.getEngineName(tableData[i])
tableData[i].ComputeResource = TrainTaskInfo.ComputeResource
tableData[i].cName=tableData[i].Name
tableData[i].rowKey = tableData[i].ID + Math.random()
tableData[i].Name=''
tableData[i].VersionCount = ''
tableData[i].Children = true
@@ -310,18 +311,18 @@ export default {
const store = this.$refs.table.store
if(!this.loadNodeMap.get(row.cName)){
const parent = store.states.data
const index = parent.findIndex(child => child.ID == row.ID)
const index = parent.findIndex(child => child.rowKey == row.rowKey)
this.getModelList()
}else{
let {tree,treeNode,resolve} = this.loadNodeMap.get(row.cName)
const keys = Object.keys(store.states.lazyTreeNodeMap);
if(keys.includes(row.ID)){
if(keys.includes(row.rowKey)){
this.getModelList()
}else{
let parentRow = store.states.data.find(child => child.cName == row.cName);
let childrenIndex = store.states.lazyTreeNodeMap[parentRow.ID].findIndex(child => child.ID == row.ID)
let childrenIndex = store.states.lazyTreeNodeMap[parentRow.rowKey].findIndex(child => child.rowKey == row.rowKey)
parentRow.VersionCount = parentRow.VersionCount-1
const parent = store.states.lazyTreeNodeMap[parentRow.ID]
const parent = store.states.lazyTreeNodeMap[parentRow.rowKey]
if(parent.length===1){
this.getModelList()
}else{
@@ -331,8 +332,8 @@ export default {
}
},
deleteModel(id,name){
let row={cName:name,ID:id}
deleteModel(id,name,rowKey){
let row={cName:name,ID:id, rowKey: rowKey}
let _this = this
let flag=1
$('.ui.basic.modal.first')
@@ -379,8 +380,8 @@ export default {
}
},
getModelList(){
try {
this.$refs.table.store.states.lazyTreeNodeMap = {}
try {
this.loadNodeMap.clear();
this.$axios.get(location.href+'_api',{
params:this.params
}).then((res)=>{
@@ -391,6 +392,7 @@ export default {
for(let i=0;i<this.tableData.length;i++){
TrainTaskInfo = JSON.parse(this.tableData[i].TrainTaskInfo)
this.tableData[i].cName=this.tableData[i].Name
this.tableData[i].rowKey=this.tableData[i].ID + Math.random()
this.tableData[i].EngineName = this.getEngineName(this.tableData[i])
this.tableData[i].ComputeResource = TrainTaskInfo.ComputeResource
this.tableData[i].hasChildren = res.data.data[i].VersionCount===1 ? false : true


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

@@ -75,8 +75,8 @@
<input
type="text"
placeholder="搜数据集名称/描述..."
v-model="search"
@keyup.enter="searchName"
v-model="search"
@keydown.enter.stop.prevent="searchName"
/>
</div>
<el-row>
@@ -727,7 +727,7 @@ export default {
"currentTree",
this.paramsCurrent.page
);
this.initCurrentTreeNode = [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) => {
@@ -742,7 +742,7 @@ export default {
);
this.$refs.currentTree.setCheckedKeys(setCheckedKeysList);
})
.catch(function (error) {
.catch((error) => {
this.loadingCurrent = false;
console.log(error);
});
@@ -763,7 +763,7 @@ export default {
"myTree",
this.paramsMy.page
);
this.initMyTreeNode = [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) => {
@@ -775,7 +775,7 @@ export default {
}, []);
this.$refs.myTree.setCheckedKeys(setCheckedKeysList);
})
.catch(function (error) {
.catch((error) => {
console.log(error);
});
},
@@ -796,7 +796,7 @@ export default {
"publicTree",
this.paramsPublics.page
);
this.initPublicTreeNode = [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) => {
@@ -808,7 +808,7 @@ export default {
}, []);
this.$refs.publicTree.setCheckedKeys(setCheckedKeysList);
})
.catch(function (error) {
.catch((error) => {
this.loadingPublic = false;
console.log(error);
});
@@ -830,7 +830,7 @@ export default {
"favoriteTree",
this.paramsFavorite.page
);
this.initFavoriteTreeNode = [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) => {
@@ -845,7 +845,7 @@ export default {
);
this.$refs.favoriteTree.setCheckedKeys(setCheckedKeysList);
})
.catch(function (error) {
.catch((error) => {
this.loadingFavorite = false;
console.log(error);
});
@@ -955,7 +955,7 @@ export default {
) {
this.benchmarkNew = true;
}
if (location.href.indexOf("modelarts/notebook/create") !== -1) {
if (location.href.indexOf("modelarts/notebook/create") !== -1 || location.href.indexOf("/cloudbrain/create") !== -1) {
this.required = false;
}
window.onresize = () => {


+ 33
- 7
web_src/js/components/images/Images.vue View File

@@ -215,16 +215,16 @@
<div style="display:flex;align-items: center;justify-content: center;">
<span v-if="scope.row.isPrivate" style="color: rgb(250, 140, 22);">私有</span>
<span v-else style="color: rgb(19, 194, 141);">公开</span>
<el-tooltip class="item" effect="dark" content="镜像提交中..." placement="top">
<i v-if="scope.row.status===0" class="CREATING" style="margin-left:0.3rem"></i>
<el-tooltip v-if="scope.row.status===0" class="item" effect="dark" content="镜像提交中..." placement="top">
<i class="CREATING" style="margin-left:0.3rem"></i>
</el-tooltip>
<el-tooltip class="item" effect="dark" content="检测提交镜像是否大小超过20G!" placement="top">
<i v-if="scope.row.status===2" class="FAILED" style="margin-left:0.3rem"></i>
<el-tooltip v-if="scope.row.status===2" class="item" effect="dark" content="检测提交镜像是否大小超过20G!" placement="top">
<i class="FAILED" style="margin-left:0.3rem"></i>
</el-tooltip>
<el-tooltip class="item" effect="dark" content="镜像提交成功" placement="top">
<i v-if="scope.row.status===1" class="SUCCEEDED" style="margin-left:0.3rem"></i>
<el-tooltip v-if="scope.row.status===1" class="item" effect="dark" content="镜像提交成功" placement="top">
<i class="SUCCEEDED" style="margin-left:0.3rem"></i>
</el-tooltip>
</div>
@@ -473,6 +473,7 @@ export default {
tableDataCustom: [],
starCustom:[],
loadingCustom:false,
refreshCustomTimer: null,

currentPageStar:1,
pageSizeStar:10,
@@ -485,6 +486,7 @@ export default {
methods: {
handleClick(tab, event) {
this.search = ''
this.stopImageListCustomRefresh();
if(tab.name=="first"){
this.paramsPublic.q = ''
this.getImageListPublic()
@@ -560,9 +562,31 @@ export default {
});
this.loadingCustom = false
this.getImageListCustomRefresh()
})
},

getImageListCustomRefresh() {
this.stopImageListCustomRefresh();
this.refreshCustomTimer = setInterval(() => {
this.tableDataCustom.forEach(item => {
if (item.status === 0) {
this.$axios.get(`/image/${item.id}`, {}).then((res) => {
const newData = res.data;
this.tableDataCustom.forEach(it => {
if (it.id === newData.id) {
it.status = newData.status;
}
});
})
}
});
}, 5000);
},

stopImageListCustomRefresh() {
this.refreshCustomTimer && clearInterval(this.refreshCustomTimer);
},
getImageListStar(){
this.loadingStar = true
this.$axios.get('/explore/images/star',{
@@ -715,8 +739,10 @@ export default {
else{
this.getImageListPublic()
}
},
beforeDestroy() {
this.stopImageListCustomRefresh();
}

};
</script>



+ 3
- 0
web_src/js/components/images/selectGrampusImages.vue View File

@@ -225,6 +225,9 @@ export default {
},
},
mounted() {
if (document.getElementById("ai_image_name")) {
this.imageAddress = document.getElementById("ai_image_name").value;
}
this.getImageListPublic();
if (
location.href.indexOf("benchmark") !== -1 ||


+ 3
- 0
web_src/js/components/images/selectImages.vue View File

@@ -498,6 +498,9 @@ export default {
},
},
mounted() {
if (document.getElementById("ai_image_name")) {
this.imageAddress = document.getElementById("ai_image_name").value;
}
this.getImageListPublic();
if (
location.href.indexOf("train-job") !== -1 ||


+ 26
- 12
web_src/js/features/clipboard.js View File

@@ -1,23 +1,37 @@
export default async function initClipboard() {
const els = document.querySelectorAll('.clipboard');
const els = document.querySelectorAll(".clipboard");
if (!els || !els.length) return;

const { default: ClipboardJS } = await import(/* webpackChunkName: "clipboard" */'clipboard');
const { default: ClipboardJS } = await import(
/* webpackChunkName: "clipboard" */ "clipboard"
);

const clipboard = new ClipboardJS(els);
clipboard.on('success', (e) => {
clipboard.on("success", (e) => {
e.clearSelection();

$(`#${e.trigger.getAttribute('id')}`).popup('destroy');
e.trigger.setAttribute('data-content', e.trigger.getAttribute('data-success'));
$(`#${e.trigger.getAttribute('id')}`).popup('show');
e.trigger.setAttribute('data-content', e.trigger.getAttribute('data-original'));
$(`#${e.trigger.getAttribute("id")}`).popup("destroy");
e.trigger.setAttribute(
"data-content",
e.trigger.getAttribute("data-success")
);
$(`#${e.trigger.getAttribute("id")}`).popup("show");
e.trigger.setAttribute(
"data-content",
e.trigger.getAttribute("data-original")
);
});

clipboard.on('error', (e) => {
$(`#${e.trigger.getAttribute('id')}`).popup('destroy');
e.trigger.setAttribute('data-content', e.trigger.getAttribute('data-error'));
$(`#${e.trigger.getAttribute('id')}`).popup('show');
e.trigger.setAttribute('data-content', e.trigger.getAttribute('data-original'));
clipboard.on("error", (e) => {
$(`#${e.trigger.getAttribute("id")}`).popup("destroy");
e.trigger.setAttribute(
"data-content",
e.trigger.getAttribute("data-error")
);
$(`#${e.trigger.getAttribute("id")}`).popup("show");
e.trigger.setAttribute(
"data-content",
e.trigger.getAttribute("data-original")
);
});
}

+ 7
- 3
web_src/js/index.js View File

@@ -2950,13 +2950,13 @@ $(document).ready(async () => {
}

const $cloneAddr = $("#clone_addr");
$cloneAddr.on("change", () => {
$cloneAddr.on("input change", () => {
const $repoName = $("#alias");
const $owner = $("#ownerDropdown div.text").attr("title");
const $urlAdd =
location.href.split("/")[0] + "//" + location.href.split("/")[2];
if ($cloneAddr.val().length > 0 && $repoName.val().length === 0) {
// Only modify if repo_name input is blank
if ($cloneAddr.val().length > 0 /* && $repoName.val().length === 0 */) {
// modify when clone address change
const repoValue = $cloneAddr.val().match(/^(.*\/)?((.+?)(\.git)?)$/)[3];
$repoName.val($cloneAddr.val().match(/^(.*\/)?((.+?)(\.git)?)$/)[3]);
$.get(
@@ -3873,6 +3873,10 @@ function initVueDataset() {
MinioUploader,
},
mounted() {
if (document.getElementById("fail_dataset_name")) {
this.dataset_name = document.getElementById("fail_dataset_name").value;
this.dataset_uuid = document.getElementById("fail_dataset_uuid").value;
}
this.getTypeList();

if (!!document.getElementById("dataset-repolink-init")) {


+ 27
- 21
web_src/less/_dataset.less View File

@@ -140,27 +140,26 @@
border: 1px solid #ffffff;
}
}
}
}
}

.item {
border-bottom: 1px solid rgba(34,36,38,.15);
border-bottom: 1px solid rgba(34, 36, 38, 0.15);
.ui.buttons {
.button {
box-shadow: none !important;
}
}
}
.ui.grid > .row {
align-items: center;
}
.title {
font-size: 16px;
font-weight: bold;
margin: 0 6px;
margin: 0 6px;
overflow: hidden;
padding-right: 15px;
white-space: nowrap;
@@ -195,7 +194,15 @@
.name {
word-break: break-all;
}

.dataset-title-a {
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
min-width: 0;
word-break: inherit !important;
margin-right: 3rem;
white-space: nowrap;
}
.metas {
color: #888888;
font-size: 14px;
@@ -222,7 +229,7 @@
}
}
}
.panel_creator_reponam{
.panel_creator_reponam {
display: inline-block;
border-radius: 4px;
padding: 4px;
@@ -231,29 +238,28 @@
background-color: rgba(161, 220, 255, 0.2);
color: #101010;
}
.panel_dataset_name{
.panel_dataset_name {
font-size: 15px;
color: #0366D6;
color: #0366d6;
text-align: center;
margin-left: 1rem;
}
.panel_datset_desc{
.panel_datset_desc {
white-space: nowrap;
display: inline-block;
overflow: hidden;
width: 90%;
text-overflow: ellipsis;
}
.el-dialog__body{
padding-top:0
.el-dialog__body {
padding-top: 0;
}
#dataset-base{
.active{
color: #0087f5!important;
border: 1px solid #0087f5!important;
#dataset-base {
.active {
color: #0087f5 !important;
border: 1px solid #0087f5 !important;
/* margin: -1px!important; */
background: #fff!important;
background: #fff !important;
}
}
}

+ 1
- 0
web_src/less/openi.less View File

@@ -311,6 +311,7 @@ footer .column {
}
.FAILED,
.START_FAILED,
.DELETED,
.CREATE_FAILED {
display: inline-block;
width: 18px;


Loading…
Cancel
Save