Browse Source

Merge branch 'V20221102' into fix-2983

pull/3062/head
zhoupzh 2 years ago
parent
commit
2ce8be2d6d
48 changed files with 1702 additions and 279 deletions
  1. +181
    -0
      models/badge.go
  2. +94
    -0
      models/badge_category.go
  3. +159
    -0
      models/badge_user.go
  4. +6
    -133
      models/cloudbrain.go
  5. +4
    -0
      models/models.go
  6. +21
    -0
      models/user.go
  7. +15
    -0
      modules/setting/setting.go
  8. +1
    -0
      options/locale/locale_en-US.ini
  9. +1
    -0
      options/locale/locale_zh-CN.ini
  10. +1
    -1
      routers/api/v1/repo/cloudbrain_dashboard.go
  11. +136
    -0
      routers/badge/badge.go
  12. +50
    -0
      routers/badge/category.go
  13. +6
    -0
      routers/repo/aisafety.go
  14. +70
    -66
      routers/repo/cloudbrain.go
  15. +9
    -2
      routers/repo/grampus.go
  16. +20
    -50
      routers/repo/modelarts.go
  17. +3
    -0
      routers/response/response_list.go
  18. +32
    -3
      routers/routes/routes.go
  19. +23
    -0
      routers/user/profile.go
  20. +38
    -0
      services/admin/operate_log/operate_log.go
  21. +80
    -0
      services/badge/badge.go
  22. +72
    -0
      services/badge/category.go
  23. +140
    -0
      services/badge/icon.go
  24. +111
    -0
      services/badge/user.go
  25. +86
    -0
      services/cloudbrain/cloudbrainTask/count.go
  26. +13
    -1
      templates/admin/cloudbrain/list.tmpl
  27. +12
    -0
      templates/custom/alert_cb.tmpl
  28. +80
    -0
      templates/org/member/members.tmpl
  29. +25
    -0
      templates/repo/badge.tmpl
  30. +1
    -0
      templates/repo/cloudbrain/benchmark/new.tmpl
  31. +1
    -0
      templates/repo/cloudbrain/inference/new.tmpl
  32. +1
    -0
      templates/repo/cloudbrain/new.tmpl
  33. +6
    -1
      templates/repo/cloudbrain/trainjob/new.tmpl
  34. +6
    -1
      templates/repo/grampus/trainjob/gpu/new.tmpl
  35. +6
    -1
      templates/repo/grampus/trainjob/npu/new.tmpl
  36. +21
    -0
      templates/repo/grampus/trainjob/show.tmpl
  37. +1
    -0
      templates/repo/modelarts/inferencejob/new.tmpl
  38. +4
    -1
      templates/repo/modelarts/notebook/new.tmpl
  39. +3
    -3
      templates/repo/modelarts/notebook/show.tmpl
  40. +11
    -1
      templates/repo/modelarts/trainjob/index.tmpl
  41. +1
    -0
      templates/repo/modelarts/trainjob/new.tmpl
  42. +12
    -8
      templates/repo/modelarts/trainjob/version_new.tmpl
  43. +1
    -0
      templates/repo/modelsafety/new.tmpl
  44. +14
    -1
      templates/user/dashboard/cloudbrains.tmpl
  45. +22
    -0
      templates/user/profile.tmpl
  46. +3
    -0
      web_src/js/features/cloudrbanin.js
  47. +11
    -4
      web_src/less/_form.less
  48. +88
    -2
      web_src/less/_user.less

+ 181
- 0
models/badge.go View File

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

import (
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
"path/filepath"
"strings"
"xorm.io/builder"
)

type Badge struct {
ID int64 `xorm:"pk autoincr"`
Name string
LightedIcon string `xorm:"varchar(2048)"`
GreyedIcon string `xorm:"varchar(2048)"`
Url string `xorm:"varchar(2048)"`
CategoryId int64
CreatedUnix timeutil.TimeStamp `xorm:"created"`
UpdatedUnix timeutil.TimeStamp `xorm:"updated"`
DeletedAt timeutil.TimeStamp `xorm:"deleted"`
}

func (m *Badge) ToUserShow() *Badge4UserShow {
return &Badge4UserShow{
Name: m.Name,
LightedIcon: GetIconOuterLink(m.LightedIcon),
GreyedIcon: GetIconOuterLink(m.GreyedIcon),
Url: m.Url,
}
}

type GetBadgeOpts struct {
BadgeType BadgeType
CategoryId int64
ListOpts ListOptions
}

type BadgeAndCategory struct {
Badge Badge `xorm:"extends"`
Category BadgeCategory `xorm:"extends"`
}

func (*BadgeAndCategory) TableName() string {
return "badge"
}

func (m *BadgeAndCategory) ToShow() *Badge4AdminShow {
return &Badge4AdminShow{
ID: m.Badge.ID,
Name: m.Badge.Name,
LightedIcon: GetIconOuterLink(m.Badge.LightedIcon),
GreyedIcon: GetIconOuterLink(m.Badge.GreyedIcon),
Url: m.Badge.Url,
CategoryName: m.Category.Name,
CategoryId: m.Category.ID,
CreatedUnix: m.Badge.CreatedUnix,
UpdatedUnix: m.Badge.UpdatedUnix,
}
}

type Badge4AdminShow struct {
ID int64
Name string
LightedIcon string
GreyedIcon string
Url string
CategoryName string
CategoryId int64
CreatedUnix timeutil.TimeStamp
UpdatedUnix timeutil.TimeStamp
}

func (m Badge4AdminShow) ToDTO() Badge {
return Badge{
Name: m.Name,
LightedIcon: m.LightedIcon,
GreyedIcon: m.GreyedIcon,
Url: m.Url,
CategoryId: m.CategoryId,
}
}

type BadgeOperateReq struct {
ID int64
Name string
LightedIcon string
GreyedIcon string
Url string
CategoryId int64
}

func (m BadgeOperateReq) ToDTO() Badge {
return Badge{
Name: m.Name,
LightedIcon: m.LightedIcon,
GreyedIcon: m.GreyedIcon,
Url: m.Url,
CategoryId: m.CategoryId,
}
}

type Badge4UserShow struct {
Name string
LightedIcon string
GreyedIcon string
Url string
}

type BadgeShowWithStatus struct {
Badge *Badge4UserShow
IsLighted bool
}

type UserAllBadgeInCategory struct {
CategoryName string
CategoryId int64
LightedNum int
Badges []*BadgeShowWithStatus
}

func GetBadgeList(opts GetBadgeOpts) (int64, []*BadgeAndCategory, error) {
if opts.ListOpts.Page <= 0 {
opts.ListOpts.Page = 1
}
var cond = builder.NewCond()
if opts.BadgeType > 0 {
cond = cond.And(builder.Eq{"badge_category.type": opts.BadgeType})
}
if opts.CategoryId > 0 {
cond = cond.And(builder.Eq{"badge_category.id": opts.CategoryId})
}
n, err := x.Join("INNER", "badge_category", "badge_category.ID = badge.category_id").Where(cond).Count(&BadgeAndCategory{})
if err != nil {
return 0, nil, err
}
r := make([]*BadgeAndCategory, 0)
if err = x.Join("INNER", "badge_category", "badge_category.ID = badge.category_id").Where(cond).OrderBy("badge.created_unix desc").Limit(opts.ListOpts.PageSize, (opts.ListOpts.Page-1)*opts.ListOpts.PageSize).Find(&r); err != nil {
return 0, nil, err
}
return n, r, nil
}

func AddBadge(m Badge) (int64, error) {
return x.Insert(&m)
}

func UpdateBadgeById(id int64, param Badge) (int64, error) {
return x.ID(id).Update(&param)
}

func DelBadge(id int64) (int64, error) {
return x.ID(id).Delete(&Badge{})
}

func GetBadgeById(id int64) (*Badge, error) {
m := &Badge{}
has, err := x.ID(id).Get(m)
if err != nil {
return nil, err
} else if !has {
return nil, &ErrRecordNotExist{}
}
return m, nil
}

func GetBadgeByCategoryId(categoryId int64) ([]*Badge, error) {
r := make([]*Badge, 0)
err := x.Where("category_id = ?", categoryId).Find(&r)
return r, err
}

func GetCustomIconByHash(hash string) string {
if len(hash) == 0 {
return ""
}
return filepath.Join(setting.IconUploadPath, hash)
}

func GetIconOuterLink(hash string) string {
return strings.TrimRight(setting.AppSubURL, "/") + "/show/icon/" + hash
}

+ 94
- 0
models/badge_category.go View File

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

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

type BadgeType int

const (
CustomizeBadge = iota + 1
SystemBadge
)

type BadgeCategory struct {
ID int64 `xorm:"pk autoincr"`
Name string
Position int64
Type BadgeType
CreatedUnix timeutil.TimeStamp `xorm:"created"`
UpdatedUnix timeutil.TimeStamp `xorm:"updated"`
DeletedAt timeutil.TimeStamp `xorm:"deleted"`
}

func (m *BadgeCategory) ToShow() *BadgeCategory4Show {
return &BadgeCategory4Show{
ID: m.ID,
Name: m.Name,
Position: m.Position,
Type: m.Type,
CreatedUnix: m.CreatedUnix,
}
}

type BadgeCategory4Show struct {
ID int64 `xorm:"pk autoincr"`
Name string
Position int64
Type BadgeType
CreatedUnix timeutil.TimeStamp `xorm:"created"`
}

func (m BadgeCategory4Show) ToDTO() BadgeCategory {
return BadgeCategory{
ID: m.ID,
Name: m.Name,
Position: m.Position,
Type: m.Type,
CreatedUnix: m.CreatedUnix,
}
}

func GetBadgeCategoryListPaging(opts ListOptions) (int64, []*BadgeCategory, error) {
n, err := x.Count(&BadgeCategory{})
if err != nil {
return 0, nil, err
}
if opts.Page <= 0 {
opts.Page = 1
}
r := make([]*BadgeCategory, 0)
if err := x.OrderBy("position asc,created_unix desc").Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).Find(&r); err != nil {
return 0, nil, err
}
return n, r, nil
}

func GetBadgeCategoryList() ([]*BadgeCategory, error) {
r := make([]*BadgeCategory, 0)
if err := x.OrderBy("position asc,created_unix desc").Find(&r); err != nil {
return nil, err
}
return r, nil
}

func AddBadgeCategory(m BadgeCategory) (int64, error) {
return x.Insert(&m)
}

func UpdateBadgeCategoryById(id int64, param BadgeCategory) (int64, error) {
return x.ID(id).Update(&param)
}

func DelBadgeCategory(id int64) (int64, error) {
return x.ID(id).Delete(&BadgeCategory{})
}

func GetBadgeCategoryById(id int64) (*BadgeCategory, error) {
m := &BadgeCategory{}
has, err := x.ID(id).Get(m)
if err != nil {
return nil, err
} else if !has {
return nil, ErrRecordNotExist{}
}
return m, nil
}

+ 159
- 0
models/badge_user.go View File

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

import (
"code.gitea.io/gitea/modules/timeutil"
"xorm.io/builder"
)

const (
ActionAddBadgeUser = 1
ActionDelBadgeUser = 2
)

type BadgeUser struct {
ID int64 `xorm:"pk autoincr"`
UserId int64 `xorm:"unique(user_badge)"`
BadgeId int64 `xorm:"unique(user_badge) index"`
CreatedUnix timeutil.TimeStamp `xorm:"created index"`
}

type BadgeUserLog struct {
ID int64 `xorm:"pk autoincr"`
UserId int64 `xorm:"index"`
BadgeId int64 `xorm:"index"`
Action int
CreatedUnix timeutil.TimeStamp `xorm:"created index"`
}

type BadgeUserDetail struct {
BadgeUser BadgeUser `xorm:"extends"`
User User `xorm:"extends"`
}

func (*BadgeUserDetail) TableName() string {
return "badge_user"
}

func (m *BadgeUserDetail) ToShow() *BadgeUser4SHow {
return &BadgeUser4SHow{
ID: m.BadgeUser.ID,
UserId: m.BadgeUser.UserId,
Name: m.User.Name,
Avatar: m.User.RelAvatarLink(),
Email: m.User.Email,
CreatedUnix: m.BadgeUser.CreatedUnix,
}
}

type BadgeUser4SHow struct {
ID int64
UserId int64
Name string
Avatar string
Email string
CreatedUnix timeutil.TimeStamp
}

type AddBadgeUsersReq struct {
BadgeId int64
Users string
}
type DelBadgeUserReq struct {
ID int64
}

type GetUserBadgesOpts struct {
CategoryId int64
ListOptions
}

func AddBadgeUser(m BadgeUser) (int64, error) {
sess := x.NewSession()
defer sess.Close()
sess.Begin()
n, err := sess.Insert(&m)
if err != nil || n == 0 {
return 0, err
}
_, err = sess.Insert(&BadgeUserLog{
UserId: m.UserId,
BadgeId: m.BadgeId,
Action: ActionAddBadgeUser,
})
if err != nil {
sess.Rollback()
return 0, err
}
return n, sess.Commit()
}

func DelBadgeUser(id int64) (int64, error) {
m := BadgeUser{}
has, err := x.ID(id).Get(&m)
if err != nil {
return 0, err
}
if !has {
return 0, ErrRecordNotExist{}
}
sess := x.NewSession()
defer sess.Close()
sess.Begin()
n, err := x.ID(m.ID).Delete(&BadgeUser{})
if err != nil || n == 0 {
return 0, err
}
_, err = sess.Insert(&BadgeUserLog{
UserId: m.UserId,
BadgeId: m.BadgeId,
Action: ActionDelBadgeUser,
})
if err != nil {
sess.Rollback()
return 0, err
}
return n, sess.Commit()
}

func GetBadgeUsers(badgeId int64, opts ListOptions) (int64, []BadgeUserDetail, error) {
n, err := x.Join("LEFT", "public.user", "public.user.ID = badge_user.user_id").Where("badge_user.badge_id = ?", badgeId).Count(&BadgeUserDetail{})
if err != nil {
return 0, nil, err
}
if opts.Page <= 0 {
opts.Page = 1
}
m := make([]BadgeUserDetail, 0)
err = x.Join("LEFT", "public.user", "public.user.ID = badge_user.user_id").Where("badge_user.badge_id = ?", badgeId).OrderBy("badge_user.id desc").Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).Find(&m)
if err != nil {
return 0, nil, err
}
return n, m, nil
}

func GetUserBadgesPaging(userId int64, opts GetUserBadgesOpts) ([]*Badge, error) {
cond := builder.NewCond()
cond = cond.And(builder.Eq{"badge_user.user_id": userId})
if opts.CategoryId > 0 {
cond = cond.And(builder.Eq{"badge.category_id": opts.CategoryId})
}

r := make([]*Badge, 0)
err := x.Join("INNER", "badge_user", "badge_user.badge_id = badge.id").Where(cond).OrderBy("badge_user.id desc").Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).Find(&r)
return r, err
}
func CountUserBadges(userId int64) (int64, error) {
return x.Where("user_id = ?", userId).Count(&BadgeUser{})
}

func GetUserBadges(userId, categoryId int64) ([]*Badge, error) {
cond := builder.NewCond()
cond = cond.And(builder.Eq{"badge_user.user_id": userId})
if categoryId > 0 {
cond = cond.And(builder.Eq{"badge.category_id": categoryId})
}

r := make([]*Badge, 0)
err := x.Join("INNER", "badge_user", "badge_user.badge_id = badge.id").Where(cond).OrderBy("badge_user.created_unix desc").Find(&r)
return r, err
}

+ 6
- 133
models/cloudbrain.go View File

@@ -2015,11 +2015,6 @@ func GetModelSafetyTestTask() ([]*Cloudbrain, error) {
return cloudbrains, err
}

func GetCloudbrainCountByUserID(userID int64, jobType string) (int, error) {
count, err := x.In("status", JobWaiting, JobRunning).And("job_type = ? and user_id = ? and type = ?", jobType, userID, TypeCloudBrainOne).Count(new(Cloudbrain))
return int(count), err
}

func GetCloudbrainRunCountByRepoID(repoID int64) (int, error) {
count, err := x.In("status", JobWaiting, JobRunning, ModelArtsCreateQueue, ModelArtsCreating, ModelArtsStarting,
ModelArtsReadyToStart, ModelArtsResizing, ModelArtsStartQueuing, ModelArtsRunning, ModelArtsDeleting, ModelArtsRestarting, ModelArtsTrainJobInit,
@@ -2028,13 +2023,8 @@ func GetCloudbrainRunCountByRepoID(repoID int64) (int, error) {
return int(count), err
}

func GetBenchmarkCountByUserID(userID int64) (int, error) {
count, err := x.In("status", JobWaiting, JobRunning).And("(job_type = ? or job_type = ? or job_type = ?) and user_id = ? and type = ?", string(JobTypeBenchmark), string(JobTypeModelSafety), string(JobTypeBrainScore), string(JobTypeSnn4imagenet), userID, TypeCloudBrainOne).Count(new(Cloudbrain))
return int(count), err
}

func GetModelSafetyCountByUserID(userID int64) (int, error) {
count, err := x.In("status", JobWaiting, JobRunning).And("job_type = ? and user_id = ?", string(JobTypeModelSafety), userID).Count(new(Cloudbrain))
count, err := x.In("status", JobWaiting, JobRunning,ModelArtsTrainJobInit,ModelArtsTrainJobImageCreating,ModelArtsTrainJobSubmitTrying,ModelArtsTrainJobScaling,ModelArtsTrainJobCheckInit,ModelArtsTrainJobCheckRunning,ModelArtsTrainJobCheckRunningCompleted).And("job_type = ? and user_id = ?", string(JobTypeModelSafety), userID).Count(new(Cloudbrain))
return int(count), err
}

@@ -2048,40 +2038,14 @@ func GetWaitingCloudbrainCount(cloudbrainType int, computeResource string, jobTy
}
return sess.Count(new(Cloudbrain))
}

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

func GetCloudbrainTrainJobCountByUserID(userID int64) (int, error) {
count, err := x.In("status", ModelArtsTrainJobInit, ModelArtsTrainJobImageCreating, ModelArtsTrainJobSubmitTrying, ModelArtsTrainJobWaiting, ModelArtsTrainJobRunning, ModelArtsTrainJobScaling, ModelArtsTrainJobCheckInit, ModelArtsTrainJobCheckRunning, ModelArtsTrainJobCheckRunningCompleted).
And("job_type = ? and user_id = ? and type = ?", JobTypeTrain, userID, TypeCloudBrainTwo).Count(new(Cloudbrain))
return int(count), err
}

func GetCloudbrainInferenceJobCountByUserID(userID int64) (int, error) {
count, err := x.In("status", ModelArtsTrainJobInit, ModelArtsTrainJobImageCreating, ModelArtsTrainJobSubmitTrying, ModelArtsTrainJobWaiting, ModelArtsTrainJobRunning, ModelArtsTrainJobScaling, ModelArtsTrainJobCheckInit, ModelArtsTrainJobCheckRunning, ModelArtsTrainJobCheckRunningCompleted).
And("job_type = ? and user_id = ? and type = ?", JobTypeInference, userID, TypeCloudBrainTwo).Count(new(Cloudbrain))
return int(count), err
}

func GetGrampusCountByUserID(userID int64, jobType, computeResource string) (int, error) {
count, err := x.In("status", GrampusStatusWaiting, GrampusStatusRunning).And("job_type = ? and user_id = ? and type = ?", jobType, userID, TypeC2Net).And("compute_resource = ?", computeResource).Count(new(Cloudbrain))
func GetNotFinalStatusTaskCount(userID int64, notFinalStatus []string, jobTypes []JobType, cloudbrainTypes []int, computeResource string) (int, error) {
count, err := x.In("status", notFinalStatus).
In("job_type", jobTypes).
In("type", cloudbrainTypes).
And("user_id = ? and compute_resource = ?", userID, computeResource).Count(new(Cloudbrain))
return int(count), err
}

func UpdateInferenceJob(job *Cloudbrain) error {
return updateInferenceJob(x, job)
}

func updateInferenceJob(e Engine, job *Cloudbrain) error {
var sess *xorm.Session
sess = e.Where("job_id = ?", job.JobID)
_, err := sess.Cols("status", "train_job_duration", "duration", "start_time", "end_time", "created_unix").Update(job)
return err
}
func RestartCloudbrain(old *Cloudbrain, new *Cloudbrain) (err error) {
sess := x.NewSession()
defer sess.Close()
@@ -2411,97 +2375,6 @@ var (
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.


+ 4
- 0
models/models.go View File

@@ -161,6 +161,10 @@ func init() {
new(CloudbrainSpec),
new(CloudbrainTemp),
new(DatasetReference),
new(BadgeCategory),
new(Badge),
new(BadgeUser),
new(BadgeUserLog),
)

tablesStatistic = append(tablesStatistic,


+ 21
- 0
models/user.go View File

@@ -2184,3 +2184,24 @@ func GetBlockChainUnSuccessUsers() ([]*User, error) {
Find(&users)
return users, err
}

//GetUserIdsByUserNames Get userIDs in batches through username paging, this method will ignore errors
func GetUserIdsByUserNames(names []string) []int64 {
pageSize := 200
length := len(names)
r := make([]int64, 0, length)
for i := 0; i < length; i = i + pageSize {
if length-i < 200 {
pageSize = length - i
}
userNameTemp := names[i : i+pageSize]
t := make([]int64, 0, length)
err := x.Table("public.user").Cols("id").In("name", userNameTemp).Find(&t)
if err != nil {
continue
}
r = append(r, t...)

}
return r
}

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

@@ -622,6 +622,13 @@ var (
DeductTaskRange time.Duration
DeductTaskRangeForFirst time.Duration

//badge config
BadgeIconMaxFileSize int64
BadgeIconMaxWidth int
BadgeIconMaxHeight int
BadgeIconDefaultSize uint
IconUploadPath string

//wechat auto reply config
UserNameOfWechatReply string
RepoNameOfWechatReply string
@@ -1531,6 +1538,14 @@ func NewContext() {
CloudBrainPayInterval = sec.Key("CLOUDBRAIN_PAY_INTERVAL").MustDuration(60 * time.Minute)
DeductTaskRange = sec.Key("DEDUCT_TASK_RANGE").MustDuration(30 * time.Minute)
DeductTaskRangeForFirst = sec.Key("DEDUCT_TASK_RANGE_FOR_FIRST").MustDuration(3 * time.Hour)

sec = Cfg.Section("icons")
BadgeIconMaxFileSize = sec.Key("BADGE_ICON_MAX_FILE_SIZE").MustInt64(1048576)
BadgeIconMaxWidth = sec.Key("BADGE_ICON_MAX_WIDTH").MustInt(4096)
BadgeIconMaxHeight = sec.Key("BADGE_ICON_MAX_HEIGHT").MustInt(3072)
BadgeIconDefaultSize = sec.Key("BADGE_ICON_DEFAULT_SIZE").MustUint(200)
IconUploadPath = sec.Key("ICON_UPLOAD_PATH").MustString(path.Join(AppDataPath, "icons"))

SetRadarMapConfig()

sec = Cfg.Section("warn_mail")


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

@@ -525,6 +525,7 @@ datasets = Datasets
activity = Public Activity
followers = Followers
starred = Starred Repositories
badge = Achievement Badge
following = Following
follow = Follow
unfollow = Unfollow


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

@@ -530,6 +530,7 @@ datasets=数据集
activity=公开活动
followers=关注者
starred=已点赞
badge=成就徽章
following=关注中
follow=关注
unfollow=取消关注


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

@@ -121,7 +121,7 @@ func GetOverviewDuration(ctx *context.Context) {
now := time.Now()
endTime := now
page := 1
pagesize := 10000
pagesize := 1000
count := pagesize
worker_server_num := 1
cardNum := 1


+ 136
- 0
routers/badge/badge.go View File

@@ -0,0 +1,136 @@
package badge

import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/routers/response"
"code.gitea.io/gitea/services/badge"
"errors"
"github.com/unknwon/com"
"net/http"
"strings"
)

func GetCustomizeBadgeList(ctx *context.Context) {
page := ctx.QueryInt("page")
category := ctx.QueryInt64("category")
pageSize := 50
n, r, err := badge.GetBadgeList(models.GetBadgeOpts{CategoryId: category, BadgeType: models.CustomizeBadge, ListOpts: models.ListOptions{PageSize: pageSize, Page: page}})
if err != nil {
log.Error("GetCustomizeBadgeList error.%v", err)
ctx.JSON(http.StatusOK, response.ServerError(err.Error()))
return
}
m := make(map[string]interface{})
m["List"] = r
m["Total"] = n
m["PageSize"] = pageSize
ctx.JSON(http.StatusOK, response.SuccessWithData(m))
}

func OperateBadge(ctx *context.Context, req models.BadgeOperateReq) {
action := ctx.Params(":action")

var err *response.BizError
switch action {
case "edit":
err = badge.EditBadge(req, ctx.User)
case "new":
err = badge.AddBadge(req, ctx.User)
case "del":
err = badge.DelBadge(req.ID, ctx.User)
default:
err = response.NewBizError(errors.New("action type error"))
}

if err != nil {
log.Error("OperateBadge error ,%v", err)
ctx.JSON(http.StatusOK, response.ResponseError(err))
return
}
ctx.JSON(http.StatusOK, response.Success())
}

func GetBadgeUsers(ctx *context.Context) {
page := ctx.QueryInt("page")
badgeId := ctx.QueryInt64("badge")
pageSize := 50
n, r, err := badge.GetBadgeUsers(badgeId, models.ListOptions{PageSize: pageSize, Page: page})
if err != nil {
log.Error("GetBadgeUsers error.%v", err)
ctx.JSON(http.StatusOK, response.ServerError(err.Error()))
return
}
m := make(map[string]interface{})
m["List"] = r
m["Total"] = n
m["PageSize"] = pageSize
ctx.JSON(http.StatusOK, response.SuccessWithData(m))
}

func AddOperateBadgeUsers(ctx *context.Context, req models.AddBadgeUsersReq) {
userStr := req.Users
if userStr == "" {
ctx.JSON(http.StatusOK, response.Success())
return
}
userStr = strings.ReplaceAll(userStr, " ", "")
userStr = strings.ReplaceAll(userStr, "\r", "")
userNames := strings.Split(userStr, "\n")
n, err := badge.AddBadgeUsers(req.BadgeId, userNames)
if err != nil {
log.Error("AddOperateBadgeUsers error.%v", err)
ctx.JSON(http.StatusOK, response.ServerError(err.Error()))
return
}
m := make(map[string]interface{})
m["Total"] = len(userNames)
m["Success"] = n
ctx.JSON(http.StatusOK, response.SuccessWithData(m))
}

func DelBadgeUsers(ctx *context.Context, req models.DelBadgeUserReq) {
id := req.ID
if id <= 0 {
ctx.JSON(http.StatusOK, response.Success())
return
}

err := badge.DelBadgeUser(id)
if err != nil {
log.Error("DelBadgeUsers error.%v", err)
ctx.JSON(http.StatusOK, response.ServerError(err.Error()))
return
}
ctx.JSON(http.StatusOK, response.Success())
}

func UploadIcon(ctx *context.Context, form badge.IconUploadForm) {

uploader := badge.NewIconUploader(badge.IconUploadConfig{
FileMaxSize: setting.BadgeIconMaxFileSize,
FileMaxWidth: setting.BadgeIconMaxWidth,
FileMaxHeight: setting.BadgeIconMaxHeight,
NeedSquare: true,
})
iconName, err := uploader.Upload(form, ctx.User)
if err != nil {
log.Error("UploadIcon error.%v", err)
ctx.JSON(http.StatusOK, response.ServerError(err.Error()))
return
}
m := make(map[string]string, 0)
m["IconName"] = iconName
ctx.JSON(http.StatusOK, response.SuccessWithData(m))
}

func GetIcon(ctx *context.Context) {
hash := ctx.Params(":hash")
if !com.IsFile(models.GetCustomIconByHash(hash)) {
ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
return
}
ctx.Redirect(setting.AppSubURL + "/icons/" + hash)
}

+ 50
- 0
routers/badge/category.go View File

@@ -0,0 +1,50 @@
package badge

import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/routers/response"
"code.gitea.io/gitea/services/badge"
"errors"
"net/http"
)

func GetBadgeCategoryList(ctx *context.Context) {
page := ctx.QueryInt("page")
pageSize := 50
n, r, err := badge.GetBadgeCategoryList(models.ListOptions{Page: page, PageSize: pageSize})
if err != nil {
log.Error("GetCategoryList error.%v", err)
ctx.JSON(http.StatusOK, response.ServerError(err.Error()))
return
}
m := make(map[string]interface{})
m["List"] = r
m["Total"] = n
m["PageSize"] = pageSize
ctx.JSON(http.StatusOK, response.SuccessWithData(m))
}

func OperateBadgeCategory(ctx *context.Context, category models.BadgeCategory4Show) {
action := ctx.Params(":action")

var err *response.BizError
switch action {
case "edit":
err = badge.EditBadgeCategory(category, ctx.User)
case "new":
err = badge.AddBadgeCategory(category, ctx.User)
case "del":
err = badge.DelBadgeCategory(category.ID, ctx.User)
default:
err = response.NewBizError(errors.New("action type error"))
}

if err != nil {
log.Error("OperateBadgeCategory error ,%v", err)
ctx.JSON(http.StatusOK, response.ResponseError(err))
return
}
ctx.JSON(http.StatusOK, response.Success())
}

+ 6
- 0
routers/repo/aisafety.go View File

@@ -535,6 +535,8 @@ func AiSafetyCreateForGetGPU(ctx *context.Context) {
} else {
log.Info("The GPU WaitCount not get")
}
NotStopTaskCount, _ := models.GetModelSafetyCountByUserID(ctx.User.ID)
ctx.Data["NotStopTaskCount"] = NotStopTaskCount
ctx.HTML(200, tplModelSafetyTestCreateGpu)
}

@@ -578,6 +580,8 @@ func AiSafetyCreateForGetNPU(ctx *context.Context) {
waitCount := cloudbrain.GetWaitingCloudbrainCount(models.TypeCloudBrainTwo, "")
ctx.Data["WaitCount"] = waitCount
log.Info("The NPU WaitCount is " + fmt.Sprint(waitCount))
NotStopTaskCount, _ := models.GetModelSafetyCountByUserID(ctx.User.ID)
ctx.Data["NotStopTaskCount"] = NotStopTaskCount
ctx.HTML(200, tplModelSafetyTestCreateNpu)
}

@@ -980,6 +984,8 @@ func modelSafetyNewDataPrepare(ctx *context.Context) error {
ctx.Data["ckpt_name"] = ctx.Query("ckpt_name")
ctx.Data["model_name"] = ctx.Query("model_name")
ctx.Data["model_version"] = ctx.Query("model_version")
NotStopTaskCount, _ := models.GetModelSafetyCountByUserID(ctx.User.ID)
ctx.Data["NotStopTaskCount"] = NotStopTaskCount

if ctx.QueryInt("type") == models.TypeCloudBrainOne {
ctx.Data["type"] = models.TypeCloudBrainOne


+ 70
- 66
routers/repo/cloudbrain.go View File

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

"code.gitea.io/gitea/modules/dataset"

"code.gitea.io/gitea/services/cloudbrain/cloudbrainTask"
"code.gitea.io/gitea/services/cloudbrain/resource"
"code.gitea.io/gitea/services/reward/point/account"

@@ -107,7 +108,7 @@ func jobNamePrefixValid(s string) string {

}

func cloudBrainNewDataPrepare(ctx *context.Context) error {
func cloudBrainNewDataPrepare(ctx *context.Context, jobType string) error {
ctx.Data["PageIsCloudBrain"] = true
t := time.Now()
var displayJobName = jobNamePrefixValid(cutString(ctx.User.Name, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:]
@@ -148,6 +149,8 @@ func cloudBrainNewDataPrepare(ctx *context.Context) error {
defaultMode = "alogrithm"
}
ctx.Data["benchmarkMode"] = defaultMode
NotStopTaskCount, _ := cloudbrainTask.GetNotFinalStatusTaskCount(ctx.User.ID, models.TypeCloudBrainOne, jobType)
ctx.Data["NotStopTaskCount"] = NotStopTaskCount

if ctx.Cloudbrain != nil {
ctx.Data["branch_name"] = ctx.Cloudbrain.BranchName
@@ -210,7 +213,7 @@ func prepareCloudbrainOneSpecs(ctx *context.Context) {
}

func CloudBrainNew(ctx *context.Context) {
err := cloudBrainNewDataPrepare(ctx)
err := cloudBrainNewDataPrepare(ctx, string(models.JobTypeDebug))
if err != nil {
ctx.ServerError("get new cloudbrain info failed", err)
return
@@ -244,7 +247,7 @@ func cloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) {
isOk, err := lock.Lock(models.CloudbrainKeyDuration)
if !isOk {
log.Error("lock processed failed:%v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_samejob_err"), tpl, &form)
return
}
@@ -254,42 +257,42 @@ func cloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) {
if err == nil {
if len(tasks) != 0 {
log.Error("the job name did already exist", ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr("the job name did already exist", tpl, &form)
return
}
} else {
if !models.IsErrJobNotExist(err) {
log.Error("system error, %v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr("system error", tpl, &form)
return
}
}

if !jobNamePattern.MatchString(displayJobName) {
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_jobname_err"), tpl, &form)
return
}

if jobType != string(models.JobTypeBenchmark) && jobType != string(models.JobTypeDebug) && jobType != string(models.JobTypeTrain) {
log.Error("jobtype error:", jobType, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr("jobtype error", tpl, &form)
return
}

count, err := models.GetCloudbrainCountByUserID(ctx.User.ID, jobType)
count, err := cloudbrainTask.GetNotFinalStatusTaskCount(ctx.User.ID, models.TypeCloudBrainOne, jobType)
if err != nil {
log.Error("GetCloudbrainCountByUserID failed:%v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr("system error", tpl, &form)
return
} else {
if count >= 1 {
log.Error("the user already has running or waiting task", ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr(ctx.Tr("repo.cloudbrain.morethanonejob"), tpl, &form)
return
}
@@ -301,7 +304,7 @@ func cloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) {
datasetInfos, datasetNames, err = models.GetDatasetInfo(uuids)
if err != nil {
log.Error("GetDatasetInfo failed: %v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr(ctx.Tr("cloudbrain.error.dataset_select"), tpl, &form)
return
}
@@ -312,7 +315,7 @@ func cloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) {
bootFileExist, err := ctx.Repo.FileExists(bootFile, branchName)
if err != nil || !bootFileExist {
log.Error("Get bootfile error:", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_bootfile_err"), tpl, &form)
return
}
@@ -320,7 +323,7 @@ func cloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) {
commandTrain, err := getTrainJobCommand(form)
if err != nil {
log.Error("getTrainJobCommand failed: %v", err)
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr(err.Error(), tpl, &form)
return
}
@@ -333,7 +336,7 @@ func cloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) {
}
errStr := loadCodeAndMakeModelPath(repo, codePath, branchName, jobName, cloudbrain.ModelMountPath)
if errStr != "" {
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr(ctx.Tr(errStr), tpl, &form)
return
}
@@ -346,14 +349,14 @@ func cloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) {
Cluster: models.OpenICluster,
AiCenterCode: models.AICenterOfCloudBrainOne})
if err != nil || spec == nil {
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr("Resource specification not available", tpl, &form)
return
}

if !account.IsPointBalanceEnough(ctx.User.ID, spec.UnitPrice) {
log.Error("point balance is not enough,userId=%d specId=%d", ctx.User.ID, spec.ID)
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr(ctx.Tr("points.insufficient_points_balance"), tpl, &form)
return
}
@@ -396,7 +399,7 @@ func cloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) {

err = cloudbrain.GenerateTask(req)
if err != nil {
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr(err.Error(), tpl, &form)
return
}
@@ -454,7 +457,7 @@ func CloudBrainInferenceJobCreate(ctx *context.Context, form auth.CreateCloudBra
isOk, err := lock.Lock(models.CloudbrainKeyDuration)
if !isOk {
log.Error("lock processed failed:%v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_samejob_err"), tpl, &form)
return
}
@@ -465,7 +468,7 @@ func CloudBrainInferenceJobCreate(ctx *context.Context, form auth.CreateCloudBra
command, err := getInferenceJobCommand(form)
if err != nil {
log.Error("getTrainJobCommand failed: %v", err)
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr(err.Error(), tpl, &form)
return
}
@@ -474,21 +477,21 @@ func CloudBrainInferenceJobCreate(ctx *context.Context, form auth.CreateCloudBra
if err == nil {
if len(tasks) != 0 {
log.Error("the job name did already exist", ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr("the job name did already exist", tpl, &form)
return
}
} else {
if !models.IsErrJobNotExist(err) {
log.Error("system error, %v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr("system error", tpl, &form)
return
}
}

if !jobNamePattern.MatchString(displayJobName) {
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_jobname_err"), tpl, &form)
return
}
@@ -496,21 +499,21 @@ func CloudBrainInferenceJobCreate(ctx *context.Context, form auth.CreateCloudBra
bootFileExist, err := ctx.Repo.FileExists(bootFile, branchName)
if err != nil || !bootFileExist {
log.Error("Get bootfile error:", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_bootfile_err"), tpl, &form)
return
}

count, err := models.GetCloudbrainCountByUserID(ctx.User.ID, jobType)
count, err := cloudbrainTask.GetNotFinalStatusTaskCount(ctx.User.ID, models.TypeCloudBrainOne, jobType)
if err != nil {
log.Error("GetCloudbrainCountByUserID failed:%v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr("system error", tpl, &form)
return
} else {
if count >= 1 {
log.Error("the user already has running or waiting task", ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr(ctx.Tr("repo.cloudbrain.morethanonejob"), tpl, &form)
return
}
@@ -521,7 +524,7 @@ func CloudBrainInferenceJobCreate(ctx *context.Context, form auth.CreateCloudBra
}
errStr := loadCodeAndMakeModelPath(repo, codePath, branchName, jobName, cloudbrain.ResultPath)
if errStr != "" {
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr(ctx.Tr(errStr), tpl, &form)
return
}
@@ -531,7 +534,7 @@ func CloudBrainInferenceJobCreate(ctx *context.Context, form auth.CreateCloudBra
datasetInfos, datasetNames, err := models.GetDatasetInfo(uuid)
if err != nil {
log.Error("GetDatasetInfo failed: %v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr(ctx.Tr("cloudbrain.error.dataset_select"), tpl, &form)
return
}
@@ -541,13 +544,13 @@ func CloudBrainInferenceJobCreate(ctx *context.Context, form auth.CreateCloudBra
Cluster: models.OpenICluster,
AiCenterCode: models.AICenterOfCloudBrainOne})
if err != nil || spec == nil {
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr("Resource specification not available", tpl, &form)
return
}
if !account.IsPointBalanceEnough(ctx.User.ID, spec.UnitPrice) {
log.Error("point balance is not enough,userId=%d specId=%d", ctx.User.ID, spec.ID)
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr(ctx.Tr("points.insufficient_points_balance"), tpl, &form)
return
}
@@ -582,7 +585,7 @@ func CloudBrainInferenceJobCreate(ctx *context.Context, form auth.CreateCloudBra

err = cloudbrain.GenerateTask(req)
if err != nil {
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr(err.Error(), tpl, &form)
return
}
@@ -682,7 +685,7 @@ func CloudBrainRestart(ctx *context.Context) {
break
}

count, err := models.GetCloudbrainCountByUserID(ctx.User.ID, string(models.JobTypeDebug))
count, err := cloudbrainTask.GetNotFinalStatusTaskCount(ctx.User.ID, models.TypeCloudBrainOne, string(models.JobTypeDebug))
if err != nil {
log.Error("GetCloudbrainCountByUserID failed:%v", err, ctx.Data["MsgID"])
resultCode = "-1"
@@ -2222,7 +2225,7 @@ func CloudBrainBenchmarkNew(ctx *context.Context) {
ctx.Data["description"] = ""
ctx.Data["benchmarkTypeID"] = -1
ctx.Data["benchmark_child_types_id_hidden"] = -1
err := cloudBrainNewDataPrepare(ctx)
err := cloudBrainNewDataPrepare(ctx, string(models.JobTypeBenchmark))
if err != nil {
ctx.ServerError("get new cloudbrain info failed", err)
return
@@ -2327,6 +2330,7 @@ func BenchMarkAlgorithmCreate(ctx *context.Context, form auth.CreateCloudBrainFo
benchmarkTypeID := form.BenchmarkTypeID
benchmarkChildTypeID := form.BenchmarkChildTypeID
repo := ctx.Repo.Repository
jobType := form.JobType

ctx.Data["description"] = form.Description
ctx.Data["benchmarkTypeID"] = benchmarkTypeID
@@ -2336,31 +2340,31 @@ func BenchMarkAlgorithmCreate(ctx *context.Context, form auth.CreateCloudBrainFo
isOk, err := lock.Lock(models.CloudbrainKeyDuration)
if !isOk {
log.Error("lock processed failed:%v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_samejob_err"), tplCloudBrainBenchmarkNew, &form)
return
}
defer lock.UnLock()

tasks, err := models.GetCloudbrainsByDisplayJobName(repo.ID, string(models.JobTypeBenchmark), displayJobName)
tasks, err := models.GetCloudbrainsByDisplayJobName(repo.ID, jobType, displayJobName)
if err == nil {
if len(tasks) != 0 {
log.Error("the job name did already exist", ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr("the job name did already exist", tplCloudBrainBenchmarkNew, &form)
return
}
} else {
if !models.IsErrJobNotExist(err) {
log.Error("system error, %v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr("system error", tplCloudBrainBenchmarkNew, &form)
return
}
}

if !jobNamePattern.MatchString(jobName) {
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_jobname_err"), tplCloudBrainBenchmarkNew, &form)
return
}
@@ -2368,7 +2372,7 @@ func BenchMarkAlgorithmCreate(ctx *context.Context, form auth.CreateCloudBrainFo
childInfo, err := getBenchmarkAttachment(benchmarkTypeID, benchmarkChildTypeID, ctx)
if err != nil {
log.Error("getBenchmarkAttachment failed:%v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr("benchmark type error", tplCloudBrainBenchmarkNew, &form)
return
}
@@ -2379,27 +2383,27 @@ func BenchMarkAlgorithmCreate(ctx *context.Context, form auth.CreateCloudBrainFo
Cluster: models.OpenICluster,
AiCenterCode: models.AICenterOfCloudBrainOne})
if err != nil || spec == nil {
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr("Resource specification not available", tplCloudBrainBenchmarkNew, &form)
return
}
if !account.IsPointBalanceEnough(ctx.User.ID, spec.UnitPrice) {
log.Error("point balance is not enough,userId=%d specId=%d", ctx.User.ID, spec.ID)
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr(ctx.Tr("points.insufficient_points_balance"), tplCloudBrainBenchmarkNew, &form)
return
}

count, err := models.GetBenchmarkCountByUserID(ctx.User.ID)
count, err := cloudbrainTask.GetNotFinalStatusTaskCount(ctx.User.ID, models.TypeCloudBrainOne, jobType)
if err != nil {
log.Error("GetCloudbrainCountByUserID failed:%v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr("system error", tplCloudBrainBenchmarkNew, &form)
return
} else {
if count >= 1 {
log.Error("the user already has running or waiting task", ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr(ctx.Tr("repo.cloudbrain.morethanonejob"), tplCloudBrainBenchmarkNew, &form)
return
}
@@ -2408,7 +2412,7 @@ func BenchMarkAlgorithmCreate(ctx *context.Context, form auth.CreateCloudBrainFo
os.RemoveAll(codePath)
if err := downloadCode(repo, codePath, cloudbrain.DefaultBranchName); err != nil {
log.Error("downloadCode failed, %v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr("system error", tplCloudBrainBenchmarkNew, &form)
return
}
@@ -2417,11 +2421,11 @@ func BenchMarkAlgorithmCreate(ctx *context.Context, form auth.CreateCloudBrainFo
if os.IsNotExist(err) {
// file does not exist
log.Error("train.py does not exist, %v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr("train.py does not exist", tplCloudBrainBenchmarkNew, &form)
} else {
log.Error("Stat failed, %v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr("system error", tplCloudBrainBenchmarkNew, &form)
}
return
@@ -2429,11 +2433,11 @@ func BenchMarkAlgorithmCreate(ctx *context.Context, form auth.CreateCloudBrainFo
if os.IsNotExist(err) {
// file does not exist
log.Error("test.py does not exist, %v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr("test.py does not exist", tplCloudBrainBenchmarkNew, &form)
} else {
log.Error("Stat failed, %v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr("system error", tplCloudBrainBenchmarkNew, &form)
}
return
@@ -2441,7 +2445,7 @@ func BenchMarkAlgorithmCreate(ctx *context.Context, form auth.CreateCloudBrainFo

if err := uploadCodeToMinio(codePath+"/", jobName, cloudbrain.CodeMountPath+"/"); err != nil {
log.Error("uploadCodeToMinio failed, %v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr("system error", tplCloudBrainBenchmarkNew, &form)
return
}
@@ -2466,7 +2470,7 @@ func BenchMarkAlgorithmCreate(ctx *context.Context, form auth.CreateCloudBrainFo
datasetInfos, datasetNames, err := models.GetDatasetInfo(uuid)
if err != nil {
log.Error("GetDatasetInfo failed: %v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr(ctx.Tr("cloudbrain.error.dataset_select"), tplCloudBrainBenchmarkNew, &form)
return
}
@@ -2500,7 +2504,7 @@ func BenchMarkAlgorithmCreate(ctx *context.Context, form auth.CreateCloudBrainFo

err = cloudbrain.GenerateTask(req)
if err != nil {
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr(err.Error(), tplCloudBrainBenchmarkNew, &form)
return
}
@@ -2526,7 +2530,7 @@ func ModelBenchmarkCreate(ctx *context.Context, form auth.CreateCloudBrainForm)
isOk, err := lock.Lock(models.CloudbrainKeyDuration)
if !isOk {
log.Error("lock processed failed:%v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_samejob_err"), tpl, &form)
return
}
@@ -2536,42 +2540,42 @@ func ModelBenchmarkCreate(ctx *context.Context, form auth.CreateCloudBrainForm)
if err == nil {
if len(tasks) != 0 {
log.Error("the job name did already exist", ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr("the job name did already exist", tpl, &form)
return
}
} else {
if !models.IsErrJobNotExist(err) {
log.Error("system error, %v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr("system error", tpl, &form)
return
}
}

if !jobNamePattern.MatchString(displayJobName) {
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_jobname_err"), tpl, &form)
return
}

if jobType != string(models.JobTypeSnn4imagenet) && jobType != string(models.JobTypeBrainScore) {
log.Error("jobtype error:", jobType, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr("jobtype error", tpl, &form)
return
}

count, err := models.GetBenchmarkCountByUserID(ctx.User.ID)
count, err := cloudbrainTask.GetNotFinalStatusTaskCount(ctx.User.ID, models.TypeCloudBrainOne, jobType)
if err != nil {
log.Error("GetCloudbrainCountByUserID failed:%v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr("system error", tpl, &form)
return
} else {
if count >= 1 {
log.Error("the user already has running or waiting task", ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr(ctx.Tr("repo.cloudbrain.morethanonejob"), tpl, &form)
return
}
@@ -2603,7 +2607,7 @@ func ModelBenchmarkCreate(ctx *context.Context, form auth.CreateCloudBrainForm)
datasetInfos, datasetNames, err := models.GetDatasetInfo(uuid)
if err != nil {
log.Error("GetDatasetInfo failed: %v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr(ctx.Tr("cloudbrain.error.dataset_select"), tpl, &form)
return
}
@@ -2613,14 +2617,14 @@ func ModelBenchmarkCreate(ctx *context.Context, form auth.CreateCloudBrainForm)
Cluster: models.OpenICluster,
AiCenterCode: models.AICenterOfCloudBrainOne})
if err != nil || spec == nil {
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr("Resource specification not available", tpl, &form)
return
}

if !account.IsPointBalanceEnough(ctx.User.ID, spec.UnitPrice) {
log.Error("point balance is not enough,userId=%d specId=%d", ctx.User.ID, spec.ID)
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr(ctx.Tr("points.insufficient_points_balance"), tpl, &form)
return
}
@@ -2654,7 +2658,7 @@ func ModelBenchmarkCreate(ctx *context.Context, form auth.CreateCloudBrainForm)

err = cloudbrain.GenerateTask(req)
if err != nil {
cloudBrainNewDataPrepare(ctx)
cloudBrainNewDataPrepare(ctx, jobType)
ctx.RenderWithErr(err.Error(), tpl, &form)
return
}
@@ -2701,7 +2705,7 @@ func CloudBrainTrainJobVersionNew(ctx *context.Context) {
}

func cloudBrainTrainJobCreate(ctx *context.Context) {
err := cloudBrainNewDataPrepare(ctx)
err := cloudBrainNewDataPrepare(ctx, string(models.JobTypeTrain))
if err != nil {
ctx.ServerError("get new train-job info failed", err)
return
@@ -2710,7 +2714,7 @@ func cloudBrainTrainJobCreate(ctx *context.Context) {
}

func InferenceCloudBrainJobNew(ctx *context.Context) {
err := cloudBrainNewDataPrepare(ctx)
err := cloudBrainNewDataPrepare(ctx, string(models.JobTypeInference))
if err != nil {
ctx.ServerError("get new train-job info failed", err)
return


+ 9
- 2
routers/repo/grampus.go View File

@@ -12,6 +12,8 @@ import (
"strings"
"time"

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

"code.gitea.io/gitea/modules/dataset"

"code.gitea.io/gitea/services/cloudbrain/resource"
@@ -135,10 +137,15 @@ func grampusTrainJobNewDataPrepare(ctx *context.Context, processType string) err
ctx.Data["datasetType"] = models.TypeCloudBrainOne
waitCount := cloudbrain.GetWaitingCloudbrainCount(models.TypeC2Net, models.GPUResource, models.JobTypeTrain)
ctx.Data["WaitCount"] = waitCount
NotStopTaskCount, _ := cloudbrainTask.GetNotFinalStatusTaskCount(ctx.User.ID, models.TypeC2Net, string(models.JobTypeTrain), models.GPUResource)
ctx.Data["NotStopTaskCount"] = NotStopTaskCount

} else if processType == grampus.ProcessorTypeNPU {
ctx.Data["datasetType"] = models.TypeCloudBrainTwo
waitCount := cloudbrain.GetWaitingCloudbrainCount(models.TypeC2Net, models.NPUResource, models.JobTypeTrain)
ctx.Data["WaitCount"] = waitCount
NotStopTaskCount, _ := cloudbrainTask.GetNotFinalStatusTaskCount(ctx.User.ID, models.TypeC2Net, string(models.JobTypeTrain), models.NPUResource)
ctx.Data["NotStopTaskCount"] = NotStopTaskCount
}

if ctx.Cloudbrain != nil {
@@ -300,7 +307,7 @@ func grampusTrainJobGpuCreate(ctx *context.Context, form auth.CreateGrampusTrain
}

//check count limit
count, err := models.GetGrampusCountByUserID(ctx.User.ID, string(models.JobTypeTrain), models.GPUResource)
count, err := cloudbrainTask.GetNotFinalStatusTaskCount(ctx.User.ID, models.TypeC2Net, string(models.JobTypeTrain), models.GPUResource)
if err != nil {
log.Error("GetGrampusCountByUserID failed:%v", err, ctx.Data["MsgID"])
grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU)
@@ -570,7 +577,7 @@ func grampusTrainJobNpuCreate(ctx *context.Context, form auth.CreateGrampusTrain
}

//check count limit
count, err := models.GetGrampusCountByUserID(ctx.User.ID, string(models.JobTypeTrain), models.NPUResource)
count, err := cloudbrainTask.GetNotFinalStatusTaskCount(ctx.User.ID, models.TypeC2Net, string(models.JobTypeTrain), models.NPUResource)
if err != nil {
log.Error("GetGrampusCountByUserID failed:%v", err, ctx.Data["MsgID"])
grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU)


+ 20
- 50
routers/repo/modelarts.go View File

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

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

"code.gitea.io/gitea/modules/dataset"

"code.gitea.io/gitea/modules/modelarts_cd"
@@ -144,6 +146,8 @@ func notebookNewDataPrepare(ctx *context.Context) error {

waitCount := cloudbrain.GetWaitingCloudbrainCount(models.TypeCloudBrainTwo, "")
ctx.Data["WaitCount"] = waitCount
NotStopTaskCount, _ := cloudbrainTask.GetNotFinalStatusTaskCount(ctx.User.ID, models.TypeCloudBrainTwo, string(models.JobTypeDebug))
ctx.Data["NotStopTaskCount"] = NotStopTaskCount

return nil
}
@@ -162,50 +166,6 @@ func prepareCloudbrainTwoDebugSpecs(ctx *context.Context) {
ctx.Data["Specs"] = noteBookSpecs
}

func NotebookCreate(ctx *context.Context, form auth.CreateModelArtsNotebookForm) {
ctx.Data["PageIsNotebook"] = true
jobName := form.JobName
uuid := form.Attachment
description := form.Description
flavor := form.Flavor

count, err := models.GetCloudbrainNotebookCountByUserID(ctx.User.ID)
if err != nil {
log.Error("GetCloudbrainNotebookCountByUserID failed:%v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr("system error", tplModelArtsNotebookNew, &form)
return
} else {
if count >= 1 {
log.Error("the user already has running or waiting task", ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr("you have already a running or waiting task, can not create more", tplModelArtsNotebookNew, &form)
return
}
}
_, err = models.GetCloudbrainByName(jobName)
if err == nil {
log.Error("the job name did already exist", ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr("the job name did already exist", tplModelArtsNotebookNew, &form)
return
} else {
if !models.IsErrJobNotExist(err) {
log.Error("system error, %v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr("system error", tplModelArtsNotebookNew, &form)
return
}
}

err = modelarts.GenerateTask(ctx, jobName, uuid, description, flavor)
if err != nil {
ctx.RenderWithErr(err.Error(), tplModelArtsNotebookNew, &form)
return
}
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob?debugListType=all")
}

func Notebook2Create(ctx *context.Context, form auth.CreateModelArtsNotebookForm) {
ctx.Data["PageIsNotebook"] = true
displayJobName := form.DisplayJobName
@@ -225,7 +185,8 @@ func Notebook2Create(ctx *context.Context, form auth.CreateModelArtsNotebookForm
}
defer lock.UnLock()

count, err := models.GetCloudbrainNotebookCountByUserID(ctx.User.ID)
count, err := cloudbrainTask.GetNotFinalStatusTaskCount(ctx.User.ID, models.TypeCloudBrainTwo, string(models.JobTypeDebug))

if err != nil {
log.Error("GetCloudbrainNotebookCountByUserID failed:%v", err, ctx.Data["MsgID"])
notebookNewDataPrepare(ctx)
@@ -272,7 +233,7 @@ func Notebook2Create(ctx *context.Context, form auth.CreateModelArtsNotebookForm
}
if !account.IsPointBalanceEnough(ctx.User.ID, spec.UnitPrice) {
log.Error("point balance is not enough,userId=%d specId=%d ", ctx.User.ID, spec.ID)
cloudBrainNewDataPrepare(ctx)
notebookNewDataPrepare(ctx)
ctx.RenderWithErr(ctx.Tr("points.insufficient_points_balance"), tplModelArtsNotebookNew, &form)
return
}
@@ -450,7 +411,8 @@ func NotebookRestart(ctx *context.Context) {
break
}

count, err := models.GetCloudbrainNotebookCountByUserID(ctx.User.ID)
count, err := cloudbrainTask.GetNotFinalStatusTaskCount(ctx.User.ID, models.TypeCloudBrainTwo, string(models.JobTypeDebug))

if err != nil {
log.Error("GetCloudbrainNotebookCountByUserID failed:%v", err, ctx.Data["MsgID"])
errorMsg = "system error"
@@ -798,6 +760,8 @@ func trainJobNewDataPrepare(ctx *context.Context) error {
ctx.Data["datasetType"] = models.TypeCloudBrainTwo
waitCount := cloudbrain.GetWaitingCloudbrainCount(models.TypeCloudBrainTwo, "")
ctx.Data["WaitCount"] = waitCount
NotStopTaskCount, _ := cloudbrainTask.GetNotFinalStatusTaskCount(ctx.User.ID, models.TypeCloudBrainTwo, string(models.JobTypeTrain))
ctx.Data["NotStopTaskCount"] = NotStopTaskCount

setMultiNodeIfConfigureMatch(ctx)

@@ -966,6 +930,8 @@ func trainJobNewVersionDataPrepare(ctx *context.Context) error {
ctx.Data["config_list"] = configList.ParaConfigs
waitCount := cloudbrain.GetWaitingCloudbrainCount(models.TypeCloudBrainTwo, "")
ctx.Data["WaitCount"] = waitCount
NotStopTaskCount, _ := cloudbrainTask.GetNotFinalStatusTaskCount(ctx.User.ID, models.TypeCloudBrainTwo, string(models.JobTypeTrain))
ctx.Data["NotStopTaskCount"] = NotStopTaskCount

return nil
}
@@ -1012,7 +978,8 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm)
}
defer lock.UnLock()

count, err := models.GetCloudbrainTrainJobCountByUserID(ctx.User.ID)
count, err := cloudbrainTask.GetNotFinalStatusTaskCount(ctx.User.ID, models.TypeCloudBrainTwo, string(models.JobTypeTrain))

if err != nil {
log.Error("GetCloudbrainTrainJobCountByUserID failed:%v", err, ctx.Data["MsgID"])
trainJobNewDataPrepare(ctx)
@@ -1356,7 +1323,7 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ
return
}

count, err := models.GetCloudbrainTrainJobCountByUserID(ctx.User.ID)
count, err := cloudbrainTask.GetNotFinalStatusTaskCount(ctx.User.ID, models.TypeCloudBrainTwo, string(models.JobTypeTrain))
if err != nil {
log.Error("GetCloudbrainTrainJobCountByUserID failed:%v", err, ctx.Data["MsgID"])
trainJobNewVersionDataPrepare(ctx)
@@ -2007,7 +1974,8 @@ func InferenceJobCreate(ctx *context.Context, form auth.CreateModelArtsInference
}
defer lock.UnLock()

count, err := models.GetCloudbrainInferenceJobCountByUserID(ctx.User.ID)
count, err := cloudbrainTask.GetNotFinalStatusTaskCount(ctx.User.ID, models.TypeCloudBrainTwo, string(models.JobTypeInference))

if err != nil {
log.Error("GetCloudbrainInferenceJobCountByUserID failed:%v", err, ctx.Data["MsgID"])
inferenceJobErrorNewDataPrepare(ctx, form)
@@ -2409,6 +2377,8 @@ func inferenceJobNewDataPrepare(ctx *context.Context) error {
ctx.Data["datasetType"] = models.TypeCloudBrainTwo
waitCount := cloudbrain.GetWaitingCloudbrainCount(models.TypeCloudBrainTwo, "")
ctx.Data["WaitCount"] = waitCount
NotStopTaskCount, _ := cloudbrainTask.GetNotFinalStatusTaskCount(ctx.User.ID, models.TypeCloudBrainTwo, string(models.JobTypeInference))
ctx.Data["NotStopTaskCount"] = NotStopTaskCount

return nil
}


+ 3
- 0
routers/response/response_list.go View File

@@ -3,3 +3,6 @@ package response
var RESOURCE_QUEUE_NOT_AVAILABLE = &BizError{Code: 1001, Err: "resource queue not available"}
var SPECIFICATION_NOT_EXIST = &BizError{Code: 1002, Err: "specification not exist"}
var SPECIFICATION_NOT_AVAILABLE = &BizError{Code: 1003, Err: "specification not available"}

var CATEGORY_STILL_HAS_BADGES = &BizError{Code: 1004, Err: "Please delete badges in the category first"}
var BADGES_STILL_HAS_USERS = &BizError{Code: 1005, Err: "Please delete users of badge first"}

+ 32
- 3
routers/routes/routes.go View File

@@ -6,6 +6,11 @@ package routes

import (
"bytes"
"code.gitea.io/gitea/routers/badge"
"code.gitea.io/gitea/routers/reward/point"
"code.gitea.io/gitea/routers/task"
badge_service "code.gitea.io/gitea/services/badge"
"code.gitea.io/gitea/services/reward"
"encoding/gob"
"net/http"
"path"
@@ -13,9 +18,6 @@ import (
"time"

"code.gitea.io/gitea/routers/modelapp"
"code.gitea.io/gitea/routers/reward/point"
"code.gitea.io/gitea/routers/task"
"code.gitea.io/gitea/services/reward"

"code.gitea.io/gitea/modules/slideimage"

@@ -196,6 +198,14 @@ func NewMacaron() *macaron.Macaron {
},
))
m.Use(public.StaticHandler(
setting.IconUploadPath,
&public.Options{
Prefix: "icons",
SkipLogging: setting.DisableRouterLog,
ExpiresAfter: setting.StaticCacheTime,
},
))
m.Use(public.StaticHandler(
setting.RepositoryAvatarUploadPath,
&public.Options{
Prefix: "repo-avatars",
@@ -522,6 +532,8 @@ func RegisterRoutes(m *macaron.Macaron) {

m.Get("/avatar/:hash", user.AvatarByEmailHash)

m.Get("/show/icon/:hash", badge.GetIcon)

adminReq := context.Toggle(&context.ToggleOptions{SignInRequired: true, AdminRequired: true})

// ***** START: Admin *****
@@ -667,6 +679,23 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Post("/add/batch", bindIgnErr(models.BatchLimitConfigVO{}), task.BatchAddTaskConfig)
m.Post("/^:action(new|edit|del)$", bindIgnErr(models.TaskConfigWithLimit{}), task.OperateTaskConfig)
})

m.Group("/badge", func() {
m.Group("/category", func() {
m.Get("/list", badge.GetBadgeCategoryList)
m.Post("/^:action(new|edit|del)$", bindIgnErr(models.BadgeCategory4Show{}), badge.OperateBadgeCategory)
})
m.Group("/customize", func() {
m.Get("/list", badge.GetCustomizeBadgeList)
})
m.Group("/users", func() {
m.Get("", badge.GetBadgeUsers)
m.Post("/add", bindIgnErr(models.AddBadgeUsersReq{}), badge.AddOperateBadgeUsers)
m.Post("/del", bindIgnErr(models.DelBadgeUserReq{}), badge.DelBadgeUsers)
})
m.Post("/^:action(new|edit|del)$", bindIgnErr(models.BadgeOperateReq{}), badge.OperateBadge)
})
m.Post("/icon/upload", bindIgnErr(badge_service.IconUploadForm{}), badge.UploadIcon)
}, operationReq)
// ***** END: Operation *****



+ 23
- 0
routers/user/profile.go View File

@@ -6,6 +6,7 @@
package user

import (
"code.gitea.io/gitea/services/badge"
"errors"
"fmt"
"path"
@@ -90,10 +91,25 @@ func Profile(ctx *context.Context) {
return
}

// Show user badges
badges, err := badge.GetUserBadges(ctxUser.ID, models.ListOptions{Page: 1, PageSize: 5})
if err != nil {
ctx.ServerError("GetUserBadges", err)
return
}
// Count user badges
cnt, err := badge.CountUserBadges(ctxUser.ID)
if err != nil {
ctx.ServerError("CountUserBadges", err)
return
}

ctx.Data["Title"] = ctxUser.DisplayName()
ctx.Data["PageIsUserProfile"] = true
ctx.Data["Owner"] = ctxUser
ctx.Data["OpenIDs"] = openIDs
ctx.Data["RecentBadges"] = badges
ctx.Data["TotalBadges"] = cnt
ctx.Data["EnableHeatmap"] = setting.Service.EnableUserHeatmap
ctx.Data["HeatmapUser"] = ctxUser.Name
showPrivate := ctx.IsSigned && (ctx.User.IsAdmin || ctx.User.ID == ctxUser.ID)
@@ -297,6 +313,13 @@ func Profile(ctx *context.Context) {
}

total = int(count)
case "badge":
allBadges, err := badge.GetUserAllBadges(ctxUser.ID)
if err != nil {
ctx.ServerError("GetUserAllBadges", err)
return
}
ctx.Data["AllBadges"] = allBadges
default:
ctx.ServerError("tab error", errors.New("tab error"))
return


+ 38
- 0
services/admin/operate_log/operate_log.go View File

@@ -4,6 +4,13 @@ import (
"code.gitea.io/gitea/models"
)

type LogBizType string

const (
BadgeCategoryOperate LogBizType = "BadgeCategoryOperate"
BadgeOperate LogBizType = "BadgeOperate"
)

func Log(log models.AdminOperateLog) error {
_, err := models.InsertAdminOperateLog(log)
return err
@@ -12,3 +19,34 @@ func Log(log models.AdminOperateLog) error {
func NewLogValues() *models.LogValues {
return &models.LogValues{Params: make([]models.LogValue, 0)}
}

func Log4Add(bizType LogBizType, newValue interface{}, doerId int64, comment string) {
Log(models.AdminOperateLog{
BizType: string(bizType),
OperateType: "add",
NewValue: NewLogValues().Add("new", newValue).JsonString(),
CreatedBy: doerId,
Comment: comment,
})
}

func Log4Edit(bizType LogBizType, oldValue interface{}, newValue interface{}, doerId int64, comment string) {
Log(models.AdminOperateLog{
BizType: string(bizType),
OperateType: "edit",
NewValue: NewLogValues().Add("new", newValue).JsonString(),
OldValue: NewLogValues().Add("old", oldValue).JsonString(),
CreatedBy: doerId,
Comment: comment,
})
}

func Log4Del(bizType LogBizType, oldValue interface{}, doerId int64, comment string) {
Log(models.AdminOperateLog{
BizType: string(bizType),
OperateType: "del",
OldValue: NewLogValues().Add("old", oldValue).JsonString(),
CreatedBy: doerId,
Comment: comment,
})
}

+ 80
- 0
services/badge/badge.go View File

@@ -0,0 +1,80 @@
package badge

import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/routers/response"
"code.gitea.io/gitea/services/admin/operate_log"
"errors"
)

func GetBadgeList(opts models.GetBadgeOpts) (int64, []*models.Badge4AdminShow, error) {
total, list, err := models.GetBadgeList(opts)
if err != nil {
return 0, nil, err
}
if len(list) == 0 {
return 0, nil, nil
}
r := make([]*models.Badge4AdminShow, len(list))
for i := 0; i < len(list); i++ {
r[i] = list[i].ToShow()
}

return total, r, nil
}

func AddBadge(m models.BadgeOperateReq, doer *models.User) *response.BizError {
_, err := models.GetBadgeCategoryById(m.CategoryId)

if err != nil {
if models.IsErrRecordNotExist(err) {
return response.NewBizError(errors.New("badge category is not available"))
}
return response.NewBizError(err)
}
_, err = models.AddBadge(m.ToDTO())
if err != nil {
return response.NewBizError(err)
}
operate_log.Log4Add(operate_log.BadgeOperate, m, doer.ID, "新增了勋章")
return nil
}

func EditBadge(m models.BadgeOperateReq, doer *models.User) *response.BizError {
if m.ID == 0 {
log.Error(" EditBadge param error")
return response.NewBizError(errors.New("param error"))
}
old, err := models.GetBadgeById(m.ID)
if err != nil {
return response.NewBizError(err)
}
_, err = models.UpdateBadgeById(m.ID, m.ToDTO())
if err != nil {
return response.NewBizError(err)
}
operate_log.Log4Edit(operate_log.BadgeOperate, old, m.ToDTO(), doer.ID, "修改了勋章")
return nil
}

func DelBadge(id int64, doer *models.User) *response.BizError {
if id == 0 {
log.Error(" DelBadge param error")
return response.NewBizError(errors.New("param error"))
}
old, err := models.GetBadgeById(id)
if err != nil {
return response.NewBizError(err)
}
n, _, err := models.GetBadgeUsers(id, models.ListOptions{PageSize: 1, Page: 1})
if err != nil {
return response.NewBizError(err)
}
if n > 0 {
return response.BADGES_STILL_HAS_USERS
}
_, err = models.DelBadge(id)
operate_log.Log4Del(operate_log.BadgeOperate, old, doer.ID, "删除了勋章")
return nil
}

+ 72
- 0
services/badge/category.go View File

@@ -0,0 +1,72 @@
package badge

import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/routers/response"
"code.gitea.io/gitea/services/admin/operate_log"
"errors"
)

func GetBadgeCategoryList(opts models.ListOptions) (int64, []*models.BadgeCategory4Show, error) {
total, list, err := models.GetBadgeCategoryListPaging(opts)
if err != nil {
return 0, nil, err
}
if len(list) == 0 {
return 0, nil, nil
}
r := make([]*models.BadgeCategory4Show, len(list))
for i := 0; i < len(list); i++ {
r[i] = list[i].ToShow()
}

return total, r, nil
}

func AddBadgeCategory(m models.BadgeCategory4Show, doer *models.User) *response.BizError {
_, err := models.AddBadgeCategory(m.ToDTO())
if err != nil {
return response.NewBizError(err)
}
operate_log.Log4Add(operate_log.BadgeCategoryOperate, m, doer.ID, "新增了勋章分类")
return nil
}

func EditBadgeCategory(m models.BadgeCategory4Show, doer *models.User) *response.BizError {
if m.ID == 0 {
log.Error(" EditBadgeCategory param error")
return response.NewBizError(errors.New("param error"))
}
old, err := models.GetBadgeCategoryById(m.ID)
if err != nil {
return response.NewBizError(err)
}
_, err = models.UpdateBadgeCategoryById(m.ID, m.ToDTO())
if err != nil {
return response.NewBizError(err)
}
operate_log.Log4Edit(operate_log.BadgeCategoryOperate, old, m.ToDTO(), doer.ID, "修改了勋章分类")
return nil
}

func DelBadgeCategory(id int64, doer *models.User) *response.BizError {
if id == 0 {
log.Error(" DelBadgeCategory param error")
return response.NewBizError(errors.New("param error"))
}
old, err := models.GetBadgeCategoryById(id)
if err != nil {
return response.NewBizError(err)
}
badges, err := models.GetBadgeByCategoryId(id)
if err != nil {
return response.NewBizError(err)
}
if len(badges) > 0 {
return response.CATEGORY_STILL_HAS_BADGES
}
_, err = models.DelBadgeCategory(id)
operate_log.Log4Del(operate_log.BadgeCategoryOperate, old, doer.ID, "删除了勋章分类")
return nil
}

+ 140
- 0
services/badge/icon.go View File

@@ -0,0 +1,140 @@
package badge

import (
"bytes"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/setting"
"crypto/md5"
"errors"
"fmt"
"github.com/nfnt/resize"
"github.com/oliamb/cutter"
"image"
"image/png"
"io/ioutil"
"mime/multipart"
"os"
)

type IconUploader struct {
Config IconUploadConfig
}

type IconUploadForm struct {
Icon *multipart.FileHeader
}

type IconUploadConfig struct {
FileMaxSize int64
FileMaxWidth int
FileMaxHeight int
DefaultSize uint
NeedResize bool
NeedSquare bool
}

func NewIconUploader(config IconUploadConfig) IconUploader {
return IconUploader{Config: config}
}

func (u IconUploader) Upload(form IconUploadForm, user *models.User) (string, error) {
if form.Icon == nil || form.Icon.Filename == "" {
return "", errors.New("File or fileName is empty")
}

fr, err := form.Icon.Open()
if err != nil {
return "", fmt.Errorf("Icon.Open: %v", err)
}
defer fr.Close()

if form.Icon.Size > u.Config.FileMaxSize {
return "", errors.New("File is too large")
}

data, err := ioutil.ReadAll(fr)
if err != nil {
return "", fmt.Errorf("ioutil.ReadAll: %v", err)
}
if !base.IsImageFile(data) {
return "", errors.New("File is not a image")
}
iconName, err := u.uploadIcon(data, user.ID)
if err != nil {
return "", fmt.Errorf("uploadIcon: %v", err)
}
return iconName, nil

}

func (u IconUploader) uploadIcon(data []byte, userId int64) (string, error) {
m, err := u.prepare(data)
if err != nil {
return "", err
}

iconName := fmt.Sprintf("%x", md5.Sum([]byte(fmt.Sprintf("%d-%x", userId, md5.Sum(data)))))

if err := os.MkdirAll(setting.IconUploadPath, os.ModePerm); err != nil {
return "", fmt.Errorf("uploadIcon. Failed to create dir %s: %v", setting.AvatarUploadPath, err)
}

fw, err := os.Create(models.GetCustomIconByHash(iconName))
if err != nil {
return "", fmt.Errorf("Create: %v", err)
}
defer fw.Close()

if err = png.Encode(fw, *m); err != nil {
return "", fmt.Errorf("Encode: %v", err)
}

return iconName, nil
}

func (u IconUploader) prepare(data []byte) (*image.Image, error) {
imgCfg, _, err := image.DecodeConfig(bytes.NewReader(data))
if err != nil {
return nil, fmt.Errorf("DecodeConfig: %v", err)
}
if imgCfg.Width > u.Config.FileMaxWidth {
return nil, fmt.Errorf("Image width is too large: %d > %d", imgCfg.Width, setting.AvatarMaxWidth)
}
if imgCfg.Height > u.Config.FileMaxHeight {
return nil, fmt.Errorf("Image height is too large: %d > %d", imgCfg.Height, setting.AvatarMaxHeight)
}

img, _, err := image.Decode(bytes.NewReader(data))
if err != nil {
return nil, fmt.Errorf("Decode: %v", err)
}

if u.Config.NeedSquare {
if imgCfg.Width != imgCfg.Height {
var newSize, ax, ay int
if imgCfg.Width > imgCfg.Height {
newSize = imgCfg.Height
ax = (imgCfg.Width - imgCfg.Height) / 2
} else {
newSize = imgCfg.Width
ay = (imgCfg.Height - imgCfg.Width) / 2
}

img, err = cutter.Crop(img, cutter.Config{
Width: newSize,
Height: newSize,
Anchor: image.Point{ax, ay},
})
if err != nil {
return nil, err
}
}
}

if u.Config.NeedResize && u.Config.DefaultSize > 0 {
img = resize.Resize(u.Config.DefaultSize, u.Config.DefaultSize, img, resize.NearestNeighbor)
}

return &img, nil
}

+ 111
- 0
services/badge/user.go View File

@@ -0,0 +1,111 @@
package badge

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

func GetBadgeUsers(badgeId int64, opts models.ListOptions) (int64, []*models.BadgeUser4SHow, error) {
total, list, err := models.GetBadgeUsers(badgeId, opts)
if err != nil {
return 0, nil, err
}
if len(list) == 0 {
return 0, nil, nil
}
r := make([]*models.BadgeUser4SHow, len(list))
for i := 0; i < len(list); i++ {
r[i] = list[i].ToShow()
}

return total, r, nil
}

func AddBadgeUsers(badgeId int64, userNames []string) (int, error) {
userIds := models.GetUserIdsByUserNames(userNames)
if len(userIds) == 0 {
return 0, nil
}
successCount := 0
for _, v := range userIds {
m := models.BadgeUser{
UserId: v,
BadgeId: badgeId,
}
_, err := models.AddBadgeUser(m)
if err != nil {
log.Error("AddBadgeUser err in loop, m=%+v. e=%v", m, err)
continue
}
successCount++
}
return successCount, nil
}

func DelBadgeUser(id int64) error {
_, err := models.DelBadgeUser(id)
return err
}

//GetUserBadges Only Returns badges the user has earned
func GetUserBadges(userId int64, opts models.ListOptions) ([]*models.Badge4UserShow, error) {
badges, err := models.GetUserBadgesPaging(userId, models.GetUserBadgesOpts{ListOptions: opts})
if err != nil {
return nil, err
}
r := make([]*models.Badge4UserShow, len(badges))
for i, v := range badges {
r[i] = v.ToUserShow()
}
return r, nil
}

func CountUserBadges(userId int64) (int64, error) {
return models.CountUserBadges(userId)
}

func GetUserAllBadges(userId int64) ([]models.UserAllBadgeInCategory, error) {
categoryList, err := models.GetBadgeCategoryList()
if err != nil {
return nil, err
}
r := make([]models.UserAllBadgeInCategory, 0)
for _, v := range categoryList {
badges, err := models.GetBadgeByCategoryId(v.ID)
if badges == nil || len(badges) == 0 {
continue
}
userBadgeMap, err := getUserBadgesMap(userId, v.ID)
if err != nil {
return nil, err
}
t := models.UserAllBadgeInCategory{
CategoryName: v.Name,
CategoryId: v.ID,
LightedNum: len(userBadgeMap),
}
bArray := make([]*models.BadgeShowWithStatus, len(badges))
for j, v := range badges {
b := &models.BadgeShowWithStatus{Badge: v.ToUserShow()}
if _, has := userBadgeMap[v.ID]; has {
b.IsLighted = true
}
bArray[j] = b
}
t.Badges = bArray
r = append(r, t)
}
return r, nil
}

func getUserBadgesMap(userId, categoryId int64) (map[int64]*models.Badge, error) {
userBadges, err := models.GetUserBadges(userId, categoryId)
if err != nil {
return nil, err
}
m := make(map[int64]*models.Badge, 0)
for _, v := range userBadges {
m[v.ID] = v
}
return m, nil
}

+ 86
- 0
services/cloudbrain/cloudbrainTask/count.go View File

@@ -0,0 +1,86 @@
package cloudbrainTask

import (
"fmt"
"strconv"

"code.gitea.io/gitea/models"
)

type StatusInfo struct {
CloudBrainTypes []int
JobType []models.JobType
NotFinalStatuses []string
ComputeResource string
}

var cloudbrainOneNotFinalStatuses = []string{string(models.JobWaiting), string(models.JobRunning)}
var cloudbrainTwoNotFinalStatuses = []string{string(models.ModelArtsTrainJobInit), string(models.ModelArtsTrainJobImageCreating), string(models.ModelArtsTrainJobSubmitTrying), string(models.ModelArtsTrainJobWaiting), string(models.ModelArtsTrainJobRunning), string(models.ModelArtsTrainJobScaling), string(models.ModelArtsTrainJobCheckInit), string(models.ModelArtsTrainJobCheckRunning), string(models.ModelArtsTrainJobCheckRunningCompleted)}
var grampusTwoNotFinalStatuses = []string{models.GrampusStatusWaiting, models.GrampusStatusRunning}
var StatusInfoDict = map[string]StatusInfo{string(models.JobTypeDebug) + "-" + strconv.Itoa(models.TypeCloudBrainOne): {
CloudBrainTypes: []int{models.TypeCloudBrainOne},
JobType: []models.JobType{models.JobTypeDebug},
NotFinalStatuses: cloudbrainOneNotFinalStatuses,
ComputeResource: models.GPUResource,
}, string(models.JobTypeTrain) + "-" + strconv.Itoa(models.TypeCloudBrainOne): {
CloudBrainTypes: []int{models.TypeCloudBrainOne},
JobType: []models.JobType{models.JobTypeTrain},
NotFinalStatuses: cloudbrainOneNotFinalStatuses,
ComputeResource: models.GPUResource,
}, string(models.JobTypeInference) + "-" + strconv.Itoa(models.TypeCloudBrainOne): {
CloudBrainTypes: []int{models.TypeCloudBrainOne},
JobType: []models.JobType{models.JobTypeInference},
NotFinalStatuses: cloudbrainOneNotFinalStatuses,
ComputeResource: models.GPUResource,
}, string(models.JobTypeBenchmark) + "-" + strconv.Itoa(models.TypeCloudBrainOne): {
CloudBrainTypes: []int{models.TypeCloudBrainOne},
JobType: []models.JobType{models.JobTypeBenchmark, models.JobTypeBrainScore, models.JobTypeSnn4imagenet},
NotFinalStatuses: cloudbrainOneNotFinalStatuses,
ComputeResource: models.GPUResource,
}, string(models.JobTypeDebug) + "-" + strconv.Itoa(models.TypeCloudBrainTwo): {
CloudBrainTypes: []int{models.TypeCloudBrainTwo, models.TypeCDCenter},
JobType: []models.JobType{models.JobTypeDebug},
NotFinalStatuses: []string{string(models.ModelArtsCreateQueue), string(models.ModelArtsCreating), string(models.ModelArtsStarting), string(models.ModelArtsReadyToStart), string(models.ModelArtsResizing), string(models.ModelArtsStartQueuing), string(models.ModelArtsRunning), string(models.ModelArtsRestarting)},
ComputeResource: models.NPUResource,
}, string(models.JobTypeTrain) + "-" + strconv.Itoa(models.TypeCloudBrainTwo): {
CloudBrainTypes: []int{models.TypeCloudBrainTwo},
JobType: []models.JobType{models.JobTypeTrain},
NotFinalStatuses: cloudbrainTwoNotFinalStatuses,
ComputeResource: models.NPUResource,
}, string(models.JobTypeInference) + "-" + strconv.Itoa(models.TypeCloudBrainTwo): {
CloudBrainTypes: []int{models.TypeCloudBrainTwo},
JobType: []models.JobType{models.JobTypeInference},
NotFinalStatuses: cloudbrainTwoNotFinalStatuses,
ComputeResource: models.NPUResource,
}, string(models.JobTypeTrain) + "-" + strconv.Itoa(models.TypeC2Net) + "-" + models.GPUResource: {
CloudBrainTypes: []int{models.TypeC2Net},
JobType: []models.JobType{models.JobTypeTrain},
NotFinalStatuses: grampusTwoNotFinalStatuses,
ComputeResource: models.GPUResource,
}, string(models.JobTypeTrain) + "-" + strconv.Itoa(models.TypeC2Net) + "-" + models.NPUResource: {
CloudBrainTypes: []int{models.TypeC2Net},
JobType: []models.JobType{models.JobTypeTrain},
NotFinalStatuses: grampusTwoNotFinalStatuses,
ComputeResource: models.NPUResource,
}}

func GetNotFinalStatusTaskCount(uid int64, cloudbrainType int, jobType string, computeResource ...string) (int, error) {
jobNewType := jobType
if jobType == string(models.JobTypeSnn4imagenet) || jobType == string(models.JobTypeBrainScore) {
jobNewType = string(models.JobTypeBenchmark)
}

key := jobNewType + "-" + strconv.Itoa(cloudbrainType)
if len(computeResource) > 0 {
key = key + "-" + computeResource[0]
}

if statusInfo, ok := StatusInfoDict[key]; ok {

return models.GetNotFinalStatusTaskCount(uid, statusInfo.NotFinalStatuses, statusInfo.JobType, statusInfo.CloudBrainTypes, statusInfo.ComputeResource)

} else {
return 0, fmt.Errorf("Can not find the status info.")
}

}

+ 13
- 1
templates/admin/cloudbrain/list.tmpl View File

@@ -283,7 +283,7 @@
</div>
<!-- 修改任务 -->
{{if eq .JobType "TRAIN"}}
<div class="ui compact buttons">
<div class="ui compact buttons __btn_edit__">
<a style="padding: 0.5rem 1rem;" class="ui basic blue button" href="{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}{{if eq .Cloudbrain.Type 1}}/modelarts/train-job/{{.JobID}}{{else if eq .Cloudbrain.Type 0}}/cloudbrain/train-job/{{.JobID}}{{else if eq .Cloudbrain.Type 2}}/grampus/train-job/{{.JobID}}{{end}}/create_version{{if .VersionName}}?version_name={{.VersionName}}{{end}}">
{{$.i18n.Tr "repo.modelarts.modify"}}
</a>
@@ -498,4 +498,16 @@
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
var editbtns = $('.__btn_edit__');
var curHref = window.location.href;
for (var i = 0, iLen = editbtns.length; i < iLen; i++) {
var buttonEl = editbtns.eq(i).find('a');
var oHref = buttonEl.attr('href');
var hasSearch = oHref.split('?').length > 1;
buttonEl.attr('href', oHref + (hasSearch ? '&' : '?') + 'backurl=' + encodeURIComponent(curHref));
}
});
</script>
{{template "base/footer" .}}

+ 12
- 0
templates/custom/alert_cb.tmpl View File

@@ -0,0 +1,12 @@
{{if .NotStopTaskCount}}
<div class="ui message" style="background-color: rgba(242, 113, 28, 0.05);border: 1px solid rgba(242, 113, 28, 1);border-radius: 5px;">
<i class="close icon"></i>
<div style="display: flex;align-items: center;">
<i class="ri-information-line" style="font-size: 35px;color: rgba(242, 113, 28, 1);;"></i>
<div style="text-align: left;margin-left: 1rem;">
<div style="font-weight: 600;line-height: 2;">您已经有 <span style="color:rgba(242, 113, 28, 1);">同类任务</span> 正在等待或运行中,请等待任务结束再创建</div>
<div style="color:#939393">可以在 “<a href="/cloudbrains" >个人中心 > 云脑任务</a>” 查看您所有的云脑任务</div>
</div>
</div>
</div>
{{end}}

+ 80
- 0
templates/org/member/members.tmpl View File

@@ -0,0 +1,80 @@
{{template "base/head" .}}
<div class="organization members">
{{template "org/header" .}}
<div class="ui container">
{{template "base/alert" .}}
{{template "org/navber" .}}
<div class="ui stackable grid">
<div class="ui sixteen wide computer column list">
{{ range .Members}}
<div class="item ui grid">
<div class="three wide mobile two wide tablet one wide computer column">
<img class="ui avatar" src="{{.SizedRelAvatarLink 48}}">
</div>
<div class="seven wide mobile three wide tablet three wide computer column">
<div class="meta"><a href="{{.HomeLink}}">{{.Name}}</a></div>
<div class="meta">{{.FullName}}</div>
</div>
<div class="ui three wide tablet four wide computer column center tablet only computer only">
<div class="meta">
{{$.i18n.Tr "org.members.membership_visibility"}}
</div>
<div class="meta">
{{ $isPublic := index $.MembersIsPublicMember .ID}}
{{if $isPublic}}
<strong>{{$.i18n.Tr "org.members.public"}}</strong>
{{if or (eq $.SignedUser.ID .ID) $.IsOrganizationOwner}}(<a class="link-action" href data-url="{{$.OrgLink}}/members/action/private?uid={{.ID}}">{{$.i18n.Tr "org.members.public_helper"}}</a>){{end}}
{{else}}
<strong>{{$.i18n.Tr "org.members.private"}}</strong>
{{if or (eq $.SignedUser.ID .ID) $.IsOrganizationOwner}}(<a class="link-action" href data-url="{{$.OrgLink}}/members/action/public?uid={{.ID}}">{{$.i18n.Tr "org.members.private_helper"}}</a>){{end}}
{{end}}
</div>
</div>
<div class="five wide mobile three wide tablet three wide computer column">
<div class="meta">
{{$.i18n.Tr "org.members.member_role"}}
</div>
<div class="meta">
<strong>{{if index $.MembersIsUserOrgOwner .ID}}{{svg "octicon-shield-lock" 16}} {{$.i18n.Tr "org.members.owner"}}{{else}}{{$.i18n.Tr "org.members.member"}}{{end}}</strong>
</div>
</div>
<div class="ui one wide column center tablet only computer only">
<div class="meta">
2FA
</div>
<div class="meta">
<strong>
{{if index $.MembersTwoFaStatus .ID}}
<span class="text green">{{svg "octicon-check" 16}}</span>
{{else}}
{{svg "octicon-x" 16}}
{{end}}
</strong>
</div>
</div>
<div class="ui three wide column tablet only computer only">
<div class="text right">
{{if eq $.SignedUser.ID .ID}}
<form method="post" action="{{$.OrgLink}}/members/action/leave">
{{$.CsrfTokenHtml}}
<button type="submit" class="ui red small button" name="uid" value="{{.ID}}">{{$.i18n.Tr "org.members.leave"}}</button>
</form>
{{else if $.IsOrganizationOwner}}
<form method="post" action="{{$.OrgLink}}/members/action/remove">
{{$.CsrfTokenHtml}}
<button type="submit" class="ui red small button" name="uid" value="{{.ID}}">{{$.i18n.Tr "org.members.remove"}}</button>
</form>
{{end}}
</div>
</div>
</div>
{{end}}
</div>
{{template "base/paginate" .}}
</div>
</div>
</div>
{{template "base/footer" .}}

+ 25
- 0
templates/repo/badge.tmpl View File

@@ -0,0 +1,25 @@
<div class="badge-achive">
{{range .AllBadges }}
<div class="bagde-section">
<div class="badge-section-title">{{.CategoryName}} &nbsp; (已点亮{{.LightedNum}}个)</div>
<div class="badge-section-children">
<div class="badge-honor-badge">
<div class="badge-honor-badge-basic">
{{range .Badges }}
<a class="badge-honor-badge-basic-item {{if not .Badge.Url}} is-not-pointer {{end}}" href="{{.Badge.Url}}">
{{if .IsLighted}}
<img src="{{.Badge.LightedIcon}}" alt="" class="badge-honor-badge-basic-img" />
{{else}}
<img src="{{.Badge.GreyedIcon}}" alt="" class="badge-honor-badge-basic-img" />
{{ end }}
<div class="badge-honor-badge-basic-txt">{{.Badge.Name}}</div>
</a>
{{ end }}
</div>
</div>
</div>
</div>
{{ end }}
{{ template "base/paginate" . }}
</div>


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

@@ -33,6 +33,7 @@
{{template "repo/header" .}}
<div class="ui container">
{{template "base/alert" .}}
{{template "custom/alert_cb" .}}
<h4 class="ui top attached header">
{{.i18n.Tr "repo.modelarts.evaluate_job.new_job"}}
</h4>


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

@@ -41,6 +41,7 @@
{{template "repo/header" .}}
<div class="ui container">
{{template "base/alert" .}}
{{template "custom/alert_cb" .}}
<div class="cloudbrain-type" style="display: none;" data-cloudbrain-type="{{.datasetType}}" data-repo-link="{{.RepoLink}}" data-queue="{{.QueuesDetail}}" data-queue-start="{{.i18n.Tr "repo.wait_count_start"}}" data-queue-end="{{.i18n.Tr "repo.wait_count_end"}}"></div>
<h4 class="ui top attached header">
{{.i18n.Tr "repo.modelarts.train_job.new_infer"}}


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

@@ -28,6 +28,7 @@
<div class="ui negative message" id="messageInfo" style="display:none;">
<p></p>
</div>
{{template "custom/alert_cb" .}}
<form id="form_id" class="ui form" action="{{.Link}}" method="post">
{{.CsrfTokenHtml}}
<input type="hidden" name='isBranches' value="{{.Branches}}">


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

@@ -72,6 +72,7 @@
<div class="ui container">
<div class="cloudbrain-type" style="display: none;" data-cloudbrain-type="{{.datasetType}}" data-repo-link="{{.RepoLink}}" data-flag-model="true" data-dataset-uuid="{{.attachment}}" data-dataset-name="{{.dataset_name}}" data-queue="{{.QueuesDetail}}" data-queue-start="{{.i18n.Tr "repo.wait_count_start"}}" data-queue-end="{{.i18n.Tr "repo.wait_count_end"}}"></div>
{{template "base/alert" .}}
{{template "custom/alert_cb" .}}
<h4 class="ui top attached header">
{{.i18n.Tr "repo.modelarts.train_job.new"}}
</h4>
@@ -234,7 +235,7 @@
<button class="ui create_train_job green button">
{{.i18n.Tr "repo.cloudbrain.new"}}
</button>
<a class="ui button"
<a class="ui button __btn-cancel-back__"
href="{{.RepoLink}}/modelarts/train-job">{{.i18n.Tr "repo.cloudbrain.cancel"}}</a>
</div>

@@ -258,5 +259,9 @@
memory: {{$.i18n.Tr "cloudbrain.memory"}},
shared_memory: {{$.i18n.Tr "cloudbrain.shared_memory"}},
});
var backUrl = new URLSearchParams(window.location.search).get("backurl");
if (backUrl) {
$('.__btn-cancel-back__').attr('href', backUrl);
}
})();
</script>

+ 6
- 1
templates/repo/grampus/trainjob/gpu/new.tmpl View File

@@ -64,6 +64,7 @@
<div class="ui container">
<div class="cloudbrain-type" style="display: none;" data-cloudbrain-type="{{.datasetType}}" data-repo-link="{{.RepoLink}}" data-flag-model="true" data-dataset-uuid="{{.attachment}}" data-dataset-name="{{.dataset_name}}"></div>
{{template "base/alert" .}}
{{template "custom/alert_cb" .}}
<h4 class="ui top attached header">
{{.i18n.Tr "repo.modelarts.train_job.new"}}
</h4>
@@ -207,7 +208,7 @@
<button class="ui create_train_job green button">
{{.i18n.Tr "repo.cloudbrain.new"}}
</button>
<a class="ui button" href="{{.RepoLink}}/modelarts/train-job">{{.i18n.Tr "repo.cloudbrain.cancel"}}</a>
<a class="ui button __btn-cancel-back__" href="{{.RepoLink}}/modelarts/train-job">{{.i18n.Tr "repo.cloudbrain.cancel"}}</a>
</div>

<!-- 模态框 -->
@@ -230,5 +231,9 @@
memory: {{$.i18n.Tr "cloudbrain.memory"}},
shared_memory: {{$.i18n.Tr "cloudbrain.shared_memory"}},
});
var backUrl = new URLSearchParams(window.location.search).get("backurl");
if (backUrl) {
$('.__btn-cancel-back__').attr('href', backUrl);
}
})();
</script>

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

@@ -59,6 +59,7 @@
<div class="ui container">
<div class="cloudbrain-type" style="display: none;" data-cloudbrain-type="{{.datasetType}}" data-repo-link="{{.RepoLink}}" data-flag-model="true" data-dataset-uuid="{{.attachment}}" data-dataset-name="{{.dataset_name}}"></div>
{{template "base/alert" .}}
{{template "custom/alert_cb" .}}
<h4 class="ui top attached header">
{{.i18n.Tr "repo.modelarts.train_job.new"}}
</h4>
@@ -231,7 +232,7 @@
<button class="ui create_train_job green button">
{{.i18n.Tr "repo.cloudbrain.new"}}
</button>
<a class="ui button" href="{{.RepoLink}}/modelarts/train-job">{{.i18n.Tr "repo.cloudbrain.cancel"}}</a>
<a class="ui button __btn-cancel-back__" href="{{.RepoLink}}/modelarts/train-job">{{.i18n.Tr "repo.cloudbrain.cancel"}}</a>
</div>

<!-- 模态框 -->
@@ -254,5 +255,9 @@
memory: {{$.i18n.Tr "cloudbrain.memory"}},
shared_memory: {{$.i18n.Tr "cloudbrain.shared_memory"}},
});
var backUrl = new URLSearchParams(window.location.search).get("backurl");
if (backUrl) {
$('.__btn-cancel-back__').attr('href', backUrl);
}
})();
</script>

+ 21
- 0
templates/repo/grampus/trainjob/show.tmpl View File

@@ -385,6 +385,26 @@
<div class="ac-grid-col">
<table class="ti-form">
<tbody class="ti-text-form">
{{ if eq $.Spec.ComputeResource "GPU"}}
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "cloudbrain.mirror"}}
</td>
<td class="ti-text-form-content">
<div class="text-span text-span-w">
<span class="ui poping up clipboard" data-position="top center" id="clipboard-btn-image" style="cursor:pointer"
data-clipboard-text="{{.EngineName}}"
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="{{.EngineName}}">{{.EngineName}}</span>
</span>
</div>
</td>
</tr>
{{else}}
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "repo.modelarts.train_job.AI_driver"}}
@@ -395,6 +415,7 @@
</div>
</td>
</tr>
{{end}}
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "repo.modelarts.code_version"}}


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

@@ -40,6 +40,7 @@
{{template "repo/header" .}}
<div class="ui container">
{{template "base/alert" .}}
{{template "custom/alert_cb" .}}
<div class="cloudbrain-type" style="display: none;" data-cloudbrain-type="1" data-repo-link="{{.RepoLink}}"></div>
<h4 class="ui top attached header">
{{.i18n.Tr "repo.modelarts.train_job.new_infer"}}


+ 4
- 1
templates/repo/modelarts/notebook/new.tmpl View File

@@ -15,6 +15,8 @@
<div class="ui negative message" id="messageInfo">
<p></p>
</div>

{{template "custom/alert_cb" .}}
<form class="ui form" id="form_id" action="{{.Link}}" method="post">
{{.CsrfTokenHtml}}
<h3 class="ui top attached header">
@@ -180,9 +182,9 @@
document.getElementById("mask").style.display = "none"
}
}

$('select.dropdown')
.dropdown();

$(function() {
$("#cloudbrain_job_type").change(function() {
if ($(this).val() == 'BENCHMARK') {
@@ -211,4 +213,5 @@
shared_memory: {{$.i18n.Tr "cloudbrain.shared_memory"}},
});
})();
console.log("-------------:",{{.NotStopTaskCount}})
</script>

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

@@ -364,9 +364,9 @@
<div class="text-span text-span-w" id="{{.VersionName}}-mirror">
<span class="ui poping up clipboard" data-position="top center" id="clipboard-btn-image" 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-success="{{$.i18n.Tr "repo.copied"}}"
data-error="{{$.i18n.Tr "repo.copied_error"}}"
data-content="{{$.i18n.Tr "repo.copy"}}"
data-variation="inverted tiny"
>
<span title="{{.Image}}">{{.Image}}</span>


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

@@ -173,7 +173,7 @@
<div class="ui compact buttons">
{{$.CsrfTokenHtml}}
{{if .CanModify}}
<a style="padding: 0.5rem 1rem;" class="ui basic blue button" href="{{if eq .Cloudbrain.Type 1}}{{$.Link}}/{{.JobID}}{{else if eq .Cloudbrain.Type 0}}{{$.RepoLink}}/cloudbrain/train-job/{{.JobID}}{{else if eq .Cloudbrain.Type 2}}{{$.RepoLink}}/grampus/train-job/{{.JobID}}{{end}}/create_version{{if .VersionName}}?version_name={{.VersionName}}{{end}}">
<a style="padding: 0.5rem 1rem;" class="ui basic blue button __btn_edit__" href="{{if eq .Cloudbrain.Type 1}}{{$.Link}}/{{.JobID}}{{else if eq .Cloudbrain.Type 0}}{{$.RepoLink}}/cloudbrain/train-job/{{.JobID}}{{else if eq .Cloudbrain.Type 2}}{{$.RepoLink}}/grampus/train-job/{{.JobID}}{{end}}/create_version{{if .VersionName}}?version_name={{.VersionName}}{{end}}">
{{$.i18n.Tr "repo.modelarts.modify"}}
</a>
{{else}}
@@ -273,4 +273,14 @@ $('.ui.selection.dropdown').dropdown({
}
})
})
document.addEventListener('DOMContentLoaded', function() {
var editbtns = $('.__btn_edit__');
var curHref = window.location.href;
for (var i = 0, iLen = editbtns.length; i < iLen; i++) {
var buttonEl = editbtns.eq(i);
var oHref = buttonEl.attr('href');
var hasSearch = oHref.split('?').length > 1;
buttonEl.attr('href', oHref + (hasSearch ? '&' : '?') + 'backurl=' + encodeURIComponent(curHref));
}
});
</script>

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

@@ -64,6 +64,7 @@
<div class="ui container">
<div class="cloudbrain-type" style="display: none;" data-cloudbrain-type="{{.datasetType}}" data-repo-link="{{.RepoLink}}" data-flag-model="true" data-dataset-uuid="{{.attachment}}" data-dataset-name="{{.dataset_name}}"></div>
{{template "base/alert" .}}
{{template "custom/alert_cb" .}}
<h4 class="ui top attached header">
{{.i18n.Tr "repo.modelarts.train_job.new"}}
</h4>


+ 12
- 8
templates/repo/modelarts/trainjob/version_new.tmpl View File

@@ -275,15 +275,19 @@
{{template "base/footer" .}}
<script src="{{StaticUrlPrefix}}/js/specsuse.js?v={{MD5 AppVer}}" type="text/javascript"></script>
<script src="{{StaticUrlPrefix}}/js/cloudbrainNew.js?v={{MD5 AppVer}}" type="text/javascript"></script>
<script>
const params = new URLSearchParams(location.search)
let version_name = params.get('create_version')
if(params.get('path')){
$('.ui.cancel.button').attr('href',location.pathname.split('/create_version')[0])
}
$("#parents_version").val(version_name)
$("input[name=version_name]").attr('value',version_name)
<script>
;(function() {
var params = new URLSearchParams(location.search);
var version_name = params.get('version_name');
if(params.get('path')){
$('.ui.cancel.button').attr('href',location.pathname.split('/create_version')[0]);
}
if(params.get('backurl')){
$('.ui.cancel.button').attr('href',params.get('backurl'));
}
$("#parents_version").val(version_name);
$("input[name=version_name]").attr('value',version_name);

var SPECS = {{ .Specs }};
var showPoint = {{ .CloudBrainPaySwitch }};
window.renderSpecsSelect($('#__specs__'), SPECS, showPoint, {


+ 1
- 0
templates/repo/modelsafety/new.tmpl View File

@@ -56,6 +56,7 @@
{{$Grampus := (or (eq (index (SubJumpablePath .Link) 1) "create_grampus_gpu") (eq (index (SubJumpablePath .Link) 1) "create_grampus_npu"))}}
<div class="cloudbrain-type" style="display: none;" data-grampus="{{$Grampus}}" data-cloudbrain-type="{{.datasetType}}" data-repo-link="{{.RepoLink}}" data-flag-model="true" data-dataset-uuid="{{.attachment}}" data-dataset-name="{{.dataset_name}}" data-queue="{{.QueuesDetail}}" data-queue-start="{{.i18n.Tr "repo.wait_count_start"}}" data-queue-end="{{.i18n.Tr "repo.wait_count_end"}}"></div>
{{template "base/alert" .}}
{{template "custom/alert_cb" .}}
<h4 class="ui top attached header">
{{.i18n.Tr "repo.modelarts.evaluate_job.new_job"}}
</h4>


+ 14
- 1
templates/user/dashboard/cloudbrains.tmpl View File

@@ -252,7 +252,7 @@
{{end}}
<!-- 修改任务 -->
{{if eq .JobType "TRAIN"}}
<div class="ui compact buttons">
<div class="ui compact buttons __btn_edit__">
<a style="padding: 0.5rem 1rem;" class="ui basic blue button" href="{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}{{if eq .Cloudbrain.Type 1}}/modelarts/train-job/{{.JobID}}{{else if eq .Cloudbrain.Type 0}}/cloudbrain/train-job/{{.JobID}}{{else if eq .Cloudbrain.Type 2}}/grampus/train-job/{{.JobID}}{{end}}/create_version{{if .VersionName}}?version_name={{.VersionName}}{{end}}">
{{$.i18n.Tr "repo.modelarts.modify"}}
</a>
@@ -446,4 +446,17 @@
</div>
</div>
</div>

<script>
document.addEventListener('DOMContentLoaded', function() {
var editbtns = $('.__btn_edit__');
var curHref = window.location.href;
for (var i = 0, iLen = editbtns.length; i < iLen; i++) {
var buttonEl = editbtns.eq(i).find('a');
var oHref = buttonEl.attr('href');
var hasSearch = oHref.split('?').length > 1;
buttonEl.attr('href', oHref + (hasSearch ? '&' : '?') + 'backurl=' + encodeURIComponent(curHref));
}
});
</script>
{{template "base/footer" .}}

+ 22
- 0
templates/user/profile.tmpl View File

@@ -17,6 +17,17 @@
{{if .Owner.FullName}}<span class="header text center">{{.Owner.FullName}}</span>{{end}}
<span class="username text center">{{.Owner.Name}}</span>
</div>
<div class="badge-wrap">
{{range $k,$v :=.RecentBadges}}
{{if le $k 3}}
<div class="badge-img-avatar" title="{{.Name}}"><img style="width: 100%;height: 100%;" src="{{.LightedIcon}}" class="ui poping up" data-content="{{.Name}}" data-position="top center" data-variation="tiny inverted"></div>
{{else}}
<a class="badge-more-icon" href="{{$.Owner.HomeLink}}?tab=badge"><i class="ri-more-fill"></i></a>
{{end}}
{{end}}
</div>
<div class="extra content wrap">
<ul class="text black">
{{if .Owner.Location}}
@@ -170,6 +181,12 @@
{{svg "octicon-person" 16}} {{.i18n.Tr "user.followers"}}
<div class="ui label">{{.Owner.NumFollowers}}</div>
</a>
<a class='{{if eq .TabName "badge"}}active{{end}} item' href="{{.Owner.HomeLink}}?tab=badge">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="16"><path fill="none" d="M0 0h24v24H0z"/><path d="M17 15.245v6.872a.5.5 0 0 1-.757.429L12 20l-4.243 2.546a.5.5 0 0 1-.757-.43v-6.87a8 8 0 1 1 10 0zM12 15a6 6 0 1 0 0-12 6 6 0 0 0 0 12zm0-2a4 4 0 1 1 0-8 4 4 0 0 1 0 8z"/></svg>
{{.i18n.Tr "user.badge"}}
<div class="ui label">{{.TotalBadges}}</div>
</a>
</div>

{{if eq .TabName "activity"}}
@@ -201,6 +218,8 @@
{{template "explore/dataset_search" .}}
{{template "explore/dataset_list" .}}
{{template "base/paginate" .}}
{{else if eq .TabName "badge"}}
{{template "repo/badge" .}}
{{else}}
{{template "explore/repo_search" .}}
{{template "explore/repo_list" .}}
@@ -228,5 +247,8 @@
.user.profile .ui.card .extra.content ul {
padding: 5px 0;
}
.ui.secondary.pointing.menu .item{
padding: 0.78571429em 0.92857143em;
}

</style>

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

@@ -575,3 +575,6 @@ function AdaminSearchControll() {
}
userSearchControll();
AdaminSearchControll();
$(".message .close").on("click", function () {
$(this).closest(".message").transition("fade");
});

+ 11
- 4
web_src/less/_form.less View File

@@ -1,8 +1,8 @@
.form {
.help {
color: #999999;
padding-top: .6em;
padding-top: 0.6em;
display: inline-block;
}
}
@@ -109,7 +109,7 @@
@media screen and (max-height: 575px) {
#rc-imageselect,
.g-recaptcha {
transform: scale(.77);
transform: scale(0.77);
transform-origin: 0 0;
}
}
@@ -141,7 +141,7 @@
}
}

input[type=number] {
input[type="number"] {
-moz-appearance: textfield;
}

@@ -157,6 +157,13 @@
&.new.repo,
&.new.migrate,
&.new.fork {
.ui.message {
@media only screen and (min-width: 768px) {
width: 800px !important;
}
margin: 0 auto;
margin-bottom: 1rem;
}
#create-page-form;

form {


+ 88
- 2
web_src/less/_user.less View File

@@ -9,11 +9,30 @@
.username {
display: block;
}

.badge-wrap {
display: flex;
justify-content: center;
align-items: center;
.badge-img-avatar {
width: 32px;
height: 32px;
margin-right: 5px;
}
.badge-more-icon {
width: 32px;
height: 32px;
display: flex;
justify-content: center;
align-items: center;
border-radius: 50%;
border: 1px #f8f9fa solid;
background: #f8f9fa;
}
}
.header {
font-weight: 700;
font-size: 1.3rem;
margin-top: -.2rem;
margin-top: -0.2rem;
line-height: 1.3rem;
}

@@ -158,3 +177,70 @@
max-width: 60px;
}
}
.badge-achive {
.bagde-section {
color: #000;
margin-top: 28px;
border-bottom: 1px solid #dededf;
}
.bagde-section:last-child {
color: #000;
margin-top: 28px;
border-bottom: none;
}
.badge-section-title {
position: relative;
font-size: 16px;
line-height: 24px;
padding-left: 8px;
margin-bottom: 20px;
display: flex;
justify-content: space-between;
}
.badge-section-children {
width: 100%;
}
.badge-honor-badge {
margin-bottom: 25px;
}
.badge-honor-badge-basic {
display: flex;
align-items: flex-start;
flex-wrap: wrap;
}
.badge-honor-badge-basic-item {
text-align: center;
font-size: 12px;
margin-right: 30px;
color: #101010;
}
.is-not-pointer {
cursor: pointer;
pointer-events: none;
}
.badge-honor-badge-basic-img {
width: 100px;
height: 100px;
margin-bottom: 10px;
}
.badge-honor-badge-basic-txt {
line-height: 20px;
width: 100px;
word-break: break-all;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.badge-section-title:before {
content: "";
position: absolute;
top: 50%;
left: 0;
transform: translateY(-50%);
width: 3px;
height: 1em;
background-color: #000;
}
}

Loading…
Cancel
Save