#4871 V20231102

Merged
ychao_1983 merged 165 commits from V20231102 into develop 6 months ago
  1. +183
    -1
      custom/public/img/logo-footer.svg
  2. +16
    -3
      entity/ai_task.go
  3. +25
    -23
      entity/cluster.go
  4. +5
    -0
      entity/creation.go
  5. +5
    -1
      manager/client/grampus/grampus.go
  6. +38
    -30
      models/cloudbrain.go
  7. +132
    -0
      models/cloudbrain_static.go
  8. +12
    -0
      models/error.go
  9. +2
    -0
      models/models.go
  10. +0
    -1
      models/repo_permission.go
  11. +17
    -0
      models/resource_specification.go
  12. +11
    -0
      models/unit.go
  13. +1
    -1
      modules/cloudbrain/cloudbrain.go
  14. +12
    -0
      modules/cron/tasks_basic.go
  15. +14
    -0
      modules/setting/setting.go
  16. +177
    -37
      modules/storage/minio_ext.go
  17. +148
    -1
      modules/storage/obs.go
  18. +1
    -5
      modules/urfs_client/objectstorage/mocks/objectstorage_mock.go
  19. +12
    -0
      options/locale/locale_en-US.ini
  20. +12
    -0
      options/locale/locale_zh-CN.ini
  21. +1
    -0
      public/img/domestic/ascend.svg
  22. +1
    -0
      public/img/domestic/cambricon.svg
  23. +1
    -0
      public/img/domestic/enflame.svg
  24. BIN
      public/img/domestic/hygon.png
  25. +1
    -0
      public/img/domestic/iluvatar.svg
  26. +1
    -0
      public/img/domestic/metax.svg
  27. +306
    -720
      public/self/dataset_preview.js
  28. +46
    -3
      routers/ai_task/ai_task.go
  29. +9
    -3
      routers/api/v1/api.go
  30. +12
    -0
      routers/api/v1/repo/attachments.go
  31. +24
    -21
      routers/api/v1/repo/cloudbrain.go
  32. +26
    -1
      routers/api/v1/repo/cloudbrain_dashboard.go
  33. +18
    -15
      routers/api/v1/repo/modelarts.go
  34. +6
    -1
      routers/home.go
  35. +33
    -13
      routers/org/teams.go
  36. +368
    -0
      routers/repo/attachment_dir.go
  37. +1
    -0
      routers/repo/dir.go
  38. +1
    -1
      routers/repo/download.go
  39. +8
    -7
      routers/repo/grampus.go
  40. +2
    -0
      routers/response/response_list.go
  41. +1
    -0
      routers/routes/routes.go
  42. +35
    -12
      services/ai_task_service/cluster/c2net.go
  43. +2
    -2
      services/ai_task_service/cluster/cloudbrain_one.go
  44. +9
    -3
      services/ai_task_service/cluster/cloudbrain_two.go
  45. +2
    -2
      services/ai_task_service/cluster/cluster_base.go
  46. +12
    -6
      services/ai_task_service/task/cloudbrain_one_notebook_task.go
  47. +29
    -21
      services/ai_task_service/task/cloudbrain_one_train_task.go
  48. +16
    -12
      services/ai_task_service/task/cloudbrain_two_train_task.go
  49. +10
    -6
      services/ai_task_service/task/grampus_notebook_task.go
  50. +11
    -7
      services/ai_task_service/task/grampus_online_infer_task.go
  51. +29
    -21
      services/ai_task_service/task/grampus_train_task.go
  52. +1
    -1
      services/ai_task_service/task/opt_handler.go
  53. +1
    -1
      services/ai_task_service/task/super_compute_task.go
  54. +8
    -4
      services/ai_task_service/task/task_base.go
  55. +27
    -5
      services/ai_task_service/task/task_creation_info.go
  56. +3
    -0
      services/ai_task_service/task/task_extend.go
  57. +51
    -0
      services/ai_task_service/task/task_service.go
  58. +1
    -0
      services/cloudbrain/resource/resource_specification.go
  59. +159
    -0
      services/cloudbrain/statistic.go
  60. +25
    -19
      templates/admin/cloudbrain/list.tmpl
  61. +2
    -0
      templates/base/head_navbar.tmpl
  62. +2
    -0
      templates/base/head_navbar_fluid.tmpl
  63. +2
    -0
      templates/base/head_navbar_home.tmpl
  64. +2
    -0
      templates/base/head_navbar_pro.tmpl
  65. +7
    -0
      templates/explore/domestic.tmpl
  66. +92
    -207
      templates/repo/datasets/dirs/dir_preview.tmpl
  67. +18
    -12
      templates/repo/datasets/dirs/index.tmpl
  68. +16
    -10
      templates/user/dashboard/cloudbrains.tmpl
  69. +46
    -2
      web_src/js/features/cloudrbanin.js
  70. +2
    -2
      web_src/js/index.js
  71. +17
    -0
      web_src/less/openi.less
  72. +16
    -0
      web_src/vuepages/apis/modules/cloudbrain.js
  73. +14
    -0
      web_src/vuepages/apis/modules/domestic.js
  74. +1
    -0
      web_src/vuepages/components/BaseDialog.vue
  75. +85
    -0
      web_src/vuepages/components/cloudbrain/DialogTips.vue
  76. +41
    -1
      web_src/vuepages/components/cloudbrain/ImageSelectV2.vue
  77. +15
    -0
      web_src/vuepages/langs/config/en-US.js
  78. +15
    -0
      web_src/vuepages/langs/config/zh-CN.js
  79. +2
    -2
      web_src/vuepages/pages/cloudbrain/configs.js
  80. +38
    -8
      web_src/vuepages/pages/cloudbrain/create/index.vue
  81. +5
    -1
      web_src/vuepages/pages/cloudbrain/detail/index.vue
  82. +2
    -0
      web_src/vuepages/pages/cloudbrain/list/index.vue
  83. +833
    -0
      web_src/vuepages/pages/explore/domestic/index.vue
  84. +17
    -0
      web_src/vuepages/pages/explore/domestic/vp-explore-domestic.js
  85. +1
    -1
      web_src/vuepages/pages/supercompute/create/index.vue

+ 183
- 1
custom/public/img/logo-footer.svg
File diff suppressed because it is too large
View File


+ 16
- 3
entity/ai_task.go View File

@@ -2,8 +2,6 @@ package entity

import (
"archive/zip"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/storage"
"encoding/json"
"fmt"
"io"
@@ -11,6 +9,10 @@ import (
"strings"
"sync"

"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/storage"
"code.gitea.io/gitea/services/role"

"code.gitea.io/gitea/models"

"code.gitea.io/gitea/modules/git"
@@ -105,6 +107,7 @@ type AITaskDetailInfo struct {
ID int64 `json:"id"`
JobID string `json:"job_id"`
Status string `json:"status"`
DetailedStatus string `json:"detailed_status"`
JobType string `json:"job_type"`
Cluster string `json:"cluster"`
DisplayJobName string `json:"display_job_name"`
@@ -151,7 +154,7 @@ func (a *AITaskDetailInfo) Tr(language string) {
}

func (a *AITaskDetailInfo) TryToRemoveDatasets(currentUser *models.User) {
if currentUser == nil || a.UserId == 0 || (!currentUser.IsAdmin && currentUser.ID != a.UserId) {
if currentUser == nil || a.UserId == 0 || (!currentUser.IsAdmin && currentUser.ID != a.UserId && !role.UserHasRole(currentUser.ID, models.MonitorAdmin)) {
a.DatasetList = []*models.DatasetDownload{}
}
}
@@ -198,10 +201,19 @@ type GetAITaskCreationInfoReq struct {
IsOnlineType bool
}

type GetAITaskCreationImageInfoReq struct {
JobType models.JobType
ClusterType ClusterType
ComputeSource *models.ComputeSource
Spec *models.Specification
UserID int64
}

type AITaskBriefInfo struct {
ID int64 `json:"id"`
JobType string `json:"job_type"`
Status string `json:"status"`
DetailedStatus string `json:"detailed_status"`
DisplayJobName string `json:"display_job_name"`
CreatedUnix timeutil.TimeStamp `json:"created_unix"`
StartTime timeutil.TimeStamp `json:"start_time"`
@@ -239,6 +251,7 @@ func ConvertCloudbrainToAITaskBriefInfo(task *models.Cloudbrain) *AITaskBriefInf
ID: task.ID,
JobType: task.JobType,
Status: task.Status,
DetailedStatus: task.DetailedStatus,
DisplayJobName: task.DisplayJobName,
CreatedUnix: task.CreatedUnix,
FormattedDuration: task.TrainJobDuration,


+ 25
- 23
entity/cluster.go View File

@@ -63,19 +63,20 @@ type CreateTrainTaskRequest struct {
}

type QueryTaskResponse struct {
StartedAt timeutil.TimeStamp `json:"started_at"`
CompletedAt timeutil.TimeStamp `json:"completed_at"`
JobId string `json:"job_id"`
Status string `json:"status"`
Url string `json:"url"`
Token string `json:"token"`
CenterId string `json:"center_id"`
CenterName string `json:"center_name"`
CodeUrl string `json:"code_url"`
DataUrl string `json:"data_url"`
ContainerIP string `json:"container_ip"`
ContainerID string `json:"container_id"`
VersionId int64 `json:"version_id"`
StartedAt timeutil.TimeStamp `json:"started_at"`
CompletedAt timeutil.TimeStamp `json:"completed_at"`
JobId string `json:"job_id"`
Status string `json:"status"`
DetailedStatus string `json:"detailed_status"`
Url string `json:"url"`
Token string `json:"token"`
CenterId string `json:"center_id"`
CenterName string `json:"center_name"`
CodeUrl string `json:"code_url"`
DataUrl string `json:"data_url"`
ContainerIP string `json:"container_ip"`
ContainerID string `json:"container_id"`
VersionId int64 `json:"version_id"`
}

func ConvertGrampusNotebookResponse(job models.GrampusNotebookInfo) *QueryTaskResponse {
@@ -100,16 +101,17 @@ func ConvertGrampusNotebookResponse(job models.GrampusNotebookInfo) *QueryTaskRe
dataUrl = t.DataUrl
}
return &QueryTaskResponse{
StartedAt: timeutil.TimeStamp(job.StartedAt),
CompletedAt: timeutil.TimeStamp(job.CompletedAt),
Status: job.Status,
CenterId: centerId,
CenterName: centerName,
Url: url,
Token: token,
JobId: job.JobID,
CodeUrl: codeUrl,
DataUrl: dataUrl,
StartedAt: timeutil.TimeStamp(job.StartedAt),
CompletedAt: timeutil.TimeStamp(job.CompletedAt),
Status: job.Status,
DetailedStatus: job.DetailedStatus,
CenterId: centerId,
CenterName: centerName,
Url: url,
Token: token,
JobId: job.JobID,
CodeUrl: codeUrl,
DataUrl: dataUrl,
}
}
func ConvertGrampusTrainResponse(job models.GrampusJobInfo) *QueryTaskResponse {


+ 5
- 0
entity/creation.go View File

@@ -21,6 +21,11 @@ type CreationRequiredInfo struct {
AllowedWorkerNum []int `json:"allowed_worker_num"`
}

type ImageRequiredInfo struct {
Images []ClusterImage `json:"images"`
CanUseAllImages bool `json:"can_use_all_images"`
}

type AITaskCreationConfig struct {
DatasetMaxSize int `json:"dataset_max_size"`
}


+ 5
- 1
manager/client/grampus/grampus.go View File

@@ -30,7 +30,8 @@ const (
urlGetImages = urlOpenApiV1 + "image"
urlNotebookJob = urlOpenApiV1 + "notebook"

errorIllegalToken = 1005
errorIllegalToken = 1005
errorCannotStopCreatingJob = 5008
)

type GetTokenParams struct {
@@ -421,6 +422,9 @@ sendjob:

if result.ErrorCode != 0 {
log.Error("GetJob failed(%d): %s", result.ErrorCode, result.ErrorMsg)
if result.ErrorCode == errorCannotStopCreatingJob {
return &result, &models.ErrCannotStopCreatingGrampusJob{}
}
return &result, fmt.Errorf("GetJob failed(%d): %s", result.ErrorCode, result.ErrorMsg)
}



+ 38
- 30
models/cloudbrain.go View File

@@ -236,8 +236,9 @@ type Cloudbrain struct {
JobName string
DisplayJobName string
Status string
UserID int64 `xorm:"INDEX NOT NULL"`
RepoID int64 `xorm:"INDEX NOT NULL"`
DetailedStatus string `xorm:"DEFAULT '-'"`
UserID int64 `xorm:"INDEX NOT NULL"`
RepoID int64 `xorm:"INDEX NOT NULL"`
SubTaskName string
ContainerID string
ContainerIp string
@@ -1593,6 +1594,7 @@ type DatasetDownload struct {
DatasetDownloadLink string `json:"dataset_download_link"`
RepositoryLink string `json:"repository_link"`
IsDelete bool `json:"is_delete"`
Size int64 `json:"size"`
}

type ModelDownload struct {
@@ -1839,31 +1841,33 @@ type GrampusResult struct {
}

type GrampusJobInfo struct {
StartedAt int64 `json:"startedAt"`
RunSec int64 `json:"runSec"`
CompletedAt int64 `json:"completedAt"`
CreatedAt int64 `json:"createdAt"`
UpdatedAt int64 `json:"updatedAt"`
Desc string `json:"desc"`
JobID string `json:"id"`
Name string `json:"name"`
Status string `json:"status"`
UserID string `json:"userId"`
Tasks []GrampusTasks `json:"tasks"`
StartedAt int64 `json:"startedAt"`
RunSec int64 `json:"runSec"`
CompletedAt int64 `json:"completedAt"`
CreatedAt int64 `json:"createdAt"`
UpdatedAt int64 `json:"updatedAt"`
Desc string `json:"desc"`
JobID string `json:"id"`
Name string `json:"name"`
Status string `json:"status"`
DetailedStatus string `json:"detailedStatus"`
UserID string `json:"userId"`
Tasks []GrampusTasks `json:"tasks"`
}

type GrampusNotebookInfo struct {
StartedAt int64 `json:"startedAt"`
RunSec int64 `json:"runSec"`
CompletedAt int64 `json:"completedAt"`
CreatedAt int64 `json:"createdAt"`
UpdatedAt int64 `json:"updatedAt"`
Desc string `json:"desc"`
JobID string `json:"id"`
Name string `json:"name"`
Status string `json:"status"`
UserID string `json:"userId"`
Tasks []GrampusNotebookTask `json:"tasks"`
StartedAt int64 `json:"startedAt"`
RunSec int64 `json:"runSec"`
CompletedAt int64 `json:"completedAt"`
CreatedAt int64 `json:"createdAt"`
UpdatedAt int64 `json:"updatedAt"`
Desc string `json:"desc"`
JobID string `json:"id"`
Name string `json:"name"`
Status string `json:"status"`
DetailedStatus string `json:"detailedStatus"`
UserID string `json:"userId"`
Tasks []GrampusNotebookTask `json:"tasks"`
}
type Center struct {
ID string `json:"id"`
@@ -1924,13 +1928,17 @@ type GetGrampusAiCentersResult struct {
Infos []GrampusAiCenter `json:"aiCenterInfos"`
TotalSize int `json:"totalSize"`
}

type AICenterImage struct {
AICenterID string `json:"aiCenterId"`
ImageUrl string `json:"imageUrl"`
}
type GrampusImage struct {
CreatedAt int64 `json:"createdAt"`
UpdatedAt int64 `json:"updatedAt"`
ID string `json:"id"`
Name string `json:"name"`
ProcessorType string `json:"processorType"`
CreatedAt int64 `json:"createdAt"`
UpdatedAt int64 `json:"updatedAt"`
ID string `json:"id"`
Name string `json:"name"`
ProcessorType string `json:"processorType"`
AICenterImage []AICenterImage `json:"aiCenterImages"`
}

type GetGrampusImagesResult struct {


+ 132
- 0
models/cloudbrain_static.go View File

@@ -15,6 +15,7 @@ type TaskDetail struct {
JobName string `json:"JobName"`
DisplayJobName string `json:"DisplayJobName"`
Status string `json:"Status"`
DetailedStatus string `json:"DetailedStatus"`
JobType string `json:"JobType"`
CreatedUnix timeutil.TimeStamp `json:"CreatedUnix"`
WaitTime string `json:"WaitTime"`
@@ -103,6 +104,137 @@ type CloudbrainAllDuration struct {
Count int `xorm:"count"`
}

type XPUInfoBase struct {
ID int64 `xorm:"pk autoincr"`
CardType string
CardTypeShow string
ResourceType string
Company string
AccessTime string
}

type XPUInfoStatistic struct {
ID int64 `xorm:"pk autoincr"`
InfoID int64 `xorm:"index"`
Type int
UsedDuration int64
UsedCardHour int64
UserCount int64
TaskCount int64
UpdatedUnix int64
}

type XPUInfoStatisticExtendBase struct {
CardType string
CardTypeShow string
ResourceType string
Company string
AccessTime string
UpdatedUnix int64
UsedCardHour int64
UserCount int64
TaskCount int64
}

func (XPUInfoStatisticExtendBase) TableName() string {
return "xpu_info_statistic"
}

type XPUInfoStatisticShow struct {
CardType string `json:"card_type"`
ResourceType string `json:"resource_type"`
Company string `json:"company"`
AccessTime string `json:"access_time"`
Count int64 `json:"count"`
UpdatedUnix int64 `json:"updated_unix"`
}

const TypeAllDays = 0
const TypeSevenDays = 1
const TypeThirtyDays = 2

var XpuInfoCategories = map[string]string{"card": "used_card_hour", "user": "user_count", "task": "task_count"}
var XpuInfoType = map[string]int{"all": TypeAllDays, "7": TypeSevenDays, "30": TypeThirtyDays}

func GetXPUInfos() ([]*XPUInfoBase, error) {
infos := make([]*XPUInfoBase, 0)
err := xStatistic.Find(&infos)
return infos, err
}

func GetXPUStatisticInfos(dataType int, category string) ([]*XPUInfoStatisticShow, error) {
statistics := make([]XPUInfoStatisticExtendBase, 0)

s := xStatistic.Where("type=?", dataType).
Join("INNER", "xpu_info_base", "xpu_info_base.id = xpu_info_statistic.info_id")
err := s.OrderBy("xpu_info_statistic." + XpuInfoCategories[category] + " desc").Find(&statistics)

if err != nil {
return nil, err
}
var result = make([]*XPUInfoStatisticShow, 0)
for _, statistic := range statistics {
item := &XPUInfoStatisticShow{
CardType: statistic.CardTypeShow,
ResourceType: statistic.ResourceType,
Company: statistic.Company,
AccessTime: statistic.AccessTime,
UpdatedUnix: statistic.UpdatedUnix,
}

if category == "card" {
item.Count = statistic.UsedCardHour
} else if category == "user" {
item.Count = statistic.UserCount
} else {
item.Count = statistic.TaskCount
}
result = append(result, item)
}
return result, nil
}

func UpdateOrInsertXPUInfoStatistic(bean *XPUInfoStatistic) error {

xpuInfoIndb := new(XPUInfoStatistic)
has, err := xStatistic.Where("info_id = ? and type=?", bean.InfoID, bean.Type).Get(xpuInfoIndb)

if err != nil {
return err
}

if has {
_, err = xStatistic.ID(xpuInfoIndb.ID).Cols("used_duration", "user_count", "used_card_hour", "task_count", "updated_unix").Update(bean)

} else {
_, err = xStatistic.Insert(bean)
}
return err

}

func HasTotalTypeXPUInfoStatisticRecord() bool {
xpuInfo := new(XPUInfoStatistic)
total, _ := xStatistic.Where("type =?", TypeAllDays).Count(xpuInfo)
return total > 0
}

func FindTotalTypeXPUInfoStatisticRecords() ([]XPUInfoStatistic, error) {

xpuInfos := make([]XPUInfoStatistic, 0)

err := xStatistic.Where("type =?", TypeAllDays).Find(&xpuInfos)
return xpuInfos, err
}
func GetTotalTypeLatestUpdateUnix() int64 {
var updated []int64
xStatistic.Table("xpu_info_statistic").Cols("updated_unix").Find(&updated)
if len(updated) > 0 {
return updated[0]
}
return 0
}

func GetTodayCreatorCount(beginTime time.Time, endTime time.Time) (int64, error) {
countSql := "SELECT count(distinct user_id) FROM " +
"public.cloudbrain where created_unix >=" + strconv.FormatInt(beginTime.Unix(), 10) +


+ 12
- 0
models/error.go View File

@@ -2082,3 +2082,15 @@ func IsErrPretrainModelNotExist(err error) bool {
func (err ErrPretrainModelNotExist) Error() string {
return fmt.Sprintf("pretrain model is not exists")
}

type ErrCannotStopCreatingGrampusJob struct {
}

func IsErrCannotStopCreatingGrampusJob(err error) bool {
_, ok := err.(ErrCannotStopCreatingGrampusJob)
return ok
}

func (err ErrCannotStopCreatingGrampusJob) Error() string {
return fmt.Sprintf("job is creating, can not be stopped")
}

+ 2
- 0
models/models.go View File

@@ -200,6 +200,8 @@ func init() {
new(ModelApp),
new(LlmChat),
new(LlmChatVisit),
new(XPUInfoBase),
new(XPUInfoStatistic),
)

gonicNames := []string{"SSL", "UID"}


+ 0
- 1
models/repo_permission.go View File

@@ -188,7 +188,6 @@ func getUserRepoPermission(e Engine, repo *Repository, user *User) (perm Permiss
}

perm.Units = repo.Units

// anonymous visit public repo
if user == nil {
perm.AccessMode = AccessModeRead


+ 17
- 0
models/resource_specification.go View File

@@ -297,6 +297,23 @@ func (s *Specification) ToShowString() string {
return specName
}

func GetAvailableCenterIdsByASpec(ID int64) ([]string, error) {
spec, err := GetResourceSpecification(&ResourceSpecification{
ID: ID})
if err != nil {
return []string{}, err
}
var queueIds []int64
err = x.Table("resource_specification").Cols("queue_id").Where("status=? and source_spec_id=?", SpecOnShelf, spec.SourceSpecId).Find(&queueIds)
if err != nil || len(queueIds) == 0 {
return []string{}, err
}
var centerIds []string
err = x.Table("resource_queue").Cols("ai_center_code").In("id", queueIds).Find(&centerIds)
return centerIds, err

}

type GetAvailableCenterIdOpts struct {
UserId int64
JobType JobType


+ 11
- 0
models/unit.go View File

@@ -60,6 +60,8 @@ func (u UnitType) String() string {
return "UnitTypeBlockChain"
case UnitTypeModelManage:
return "UnitTypeModelManage"
case UnitTypeHPC:
return "UnitTypeHPC"
}
return fmt.Sprintf("Unknown UnitType %d", u)
}
@@ -297,6 +299,14 @@ var (
8,
}

UnitHPC = Unit{
UnitTypeHPC,
"repo.hpc",
"/supercompute",
"repo.hpc.desc",
9,
}

// Units contains all the units
Units = map[UnitType]Unit{
UnitTypeCode: UnitCode,
@@ -310,6 +320,7 @@ var (
UnitTypeCloudBrain: UnitCloudBrain,
UnitTypeBlockChain: UnitBlockChain,
UnitTypeModelManage: UnitModelManage,
UnitTypeHPC: UnitHPC,
}
)



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

@@ -120,7 +120,7 @@ func CanModifyJob(ctx *context.Context, job *models.Cloudbrain) bool {
return isAdminOrJobCreater(ctx, job, nil)
}
func CanDownloadJob(ctx *context.Context, job *models.Cloudbrain) bool {
return isAdminOrJobCreater(ctx, job, nil)
return isAdminOrOwnerOrJobCreater(ctx, job, nil)
}

func isAdminOrJobCreater(ctx *context.Context, job *models.Cloudbrain, err error) bool {


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

@@ -230,6 +230,17 @@ func registerHandleSummaryStatistic() {
return nil
})
}
func registerHandleCardStatistic() {
RegisterTaskFatal("handle_card_statistic", &BaseConfig{
Enabled: setting.CardStatistic.Enabled,
RunAtStart: setting.CardStatistic.RunAtStart,
Schedule: setting.CardStatistic.Cron,
}, func(ctx context.Context, _ *models.User, _ Config) error {
cloudbrainService.CardStatistic()
return nil
})

}

func registerHandleOrgStatistic() {
RegisterTaskFatal("handle_org_statistic", &BaseConfig{
@@ -411,4 +422,5 @@ func initBasicTasks() {

registerSyncFinetunePanguDeployStatus()
registerFinetunePanguServiceCreateQueue()
registerHandleCardStatistic()
}

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

@@ -659,6 +659,11 @@ var (
Cron string
RunAtStart bool
}{}
CardStatistic = struct {
Enabled bool
Cron string
RunAtStart bool
}{}

C2NetInfos *C2NetSqInfos
CenterInfos *AiCenterInfos
@@ -1785,6 +1790,7 @@ func NewContext() {
getModelAppConfig()
getClearStrategy()
getNotebookStrategy()
getCardStatistic()
NewScreenMapConfig()
}

@@ -1904,6 +1910,14 @@ func getNotebookStrategy() {
NotebookStrategy.RunAtStart = sec.Key("RUN_AT_START").MustBool(false)
}

func getCardStatistic() {

sec := Cfg.Section("card_statistic")
CardStatistic.Enabled = sec.Key("ENABLED").MustBool(false)
CardStatistic.Cron = sec.Key("CRON").MustString("@daily")
CardStatistic.RunAtStart = sec.Key("RUN_AT_START").MustBool(false)
}

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



+ 177
- 37
modules/storage/minio_ext.go View File

@@ -175,53 +175,62 @@ func GetOneLevelAllObjectUnderDirMinio(bucket string, prefixRootPath string, rel
Prefix += "/"
}
log.Info("bucket=" + bucket + " Prefix=" + Prefix)
output, err := core.ListObjects(bucket, Prefix, "", "", 1000)
marker := ""
fileInfos := make([]FileInfo, 0)
prefixLen := len(Prefix)
fileMap := make(map[string]bool, 0)
if err == nil {
for _, val := range output.Contents {

log.Info("val key=" + val.Key)
var isDir bool
var fileName string
if val.Key == Prefix {
continue
}
fileName = val.Key[prefixLen:]
log.Info("fileName =" + fileName)
files := strings.Split(fileName, "/")
if fileMap[files[0]] {
continue
} else {
fileMap[files[0]] = true
index := 1
for {
output, err := core.ListObjects(bucket, Prefix, marker, "", 1000)
if err == nil {
log.Info("Page:%d\n", index)
index++
for _, val := range output.Contents {
log.Info("val key=" + val.Key)
var isDir bool
var fileName string
if val.Key == Prefix {
continue
}
fileName = val.Key[prefixLen:]
log.Info("fileName =" + fileName)
files := strings.Split(fileName, "/")
if fileMap[files[0]] {
continue
} else {
fileMap[files[0]] = true
}
ParenDir := relativePath
fileName = files[0]
if len(files) > 1 {
isDir = true
ParenDir += fileName + "/"
} else {
isDir = false
}
fileInfo := FileInfo{
ModTime: val.LastModified.Local().Format("2006-01-02 15:04:05"),
FileName: fileName,
Size: val.Size,
IsDir: isDir,
ParenDir: ParenDir,
}
fileInfos = append(fileInfos, fileInfo)
}
ParenDir := relativePath
fileName = files[0]
if len(files) > 1 {
isDir = true
ParenDir += fileName + "/"
if output.IsTruncated {
marker = output.NextMarker
} else {
isDir = false
break
}

fileInfo := FileInfo{
ModTime: val.LastModified.Local().Format("2006-01-02 15:04:05"),
FileName: fileName,
Size: val.Size,
IsDir: isDir,
ParenDir: ParenDir,
}
fileInfos = append(fileInfos, fileInfo)
}
return fileInfos, err
} else {
} else {

log.Error("Message:%s", err.Error())
log.Error("Message:%s", err.Error())

return nil, err
return nil, err
}
}
return fileInfos, err
}

func MinioGetFilesSize(bucketName string, Files []string) int64 {
@@ -422,3 +431,134 @@ func MinioCheckAndGetFileSize(srcBucket string, key string) (bool, int64) {
}
return true, meta.Size
}

func GetDirsListMinio(bucket string, prefixRootPath string, prefix string, dirLevel int) ([]string, error) {
_, core, err := getClients()
if err != nil {
log.Error("getClients failed:", err.Error())
return nil, err
}
minioPrefix := prefixRootPath + prefix
if !strings.HasSuffix(minioPrefix, "/") {
minioPrefix += "/"
}
prefixLen := len(minioPrefix)
delimiter := ""
marker := ""
index := 1
fileMap := make(map[string]bool, 0)
log.Info("buckent=" + bucket + " minioPrefix=" + minioPrefix)
for {
output, err := core.ListObjects(bucket, minioPrefix, marker, delimiter, 1000)
if err == nil {
log.Info("Page:%d\n", index)
index++
for _, val := range output.Contents {
fileName := val.Key[prefixLen:]
files := strings.Split(fileName, "/")
currentLevel := 0
for {
if currentLevel >= dirLevel || currentLevel >= (len(files)-1) {
break
}
path := getPathFromPathArrays(files, currentLevel)
if !fileMap[path] {
fileMap[path] = true
}
currentLevel = currentLevel + 1
}
}
if output.IsTruncated {
marker = output.NextMarker
} else {
break
}
} else {
log.Info("list error." + err.Error())
return nil, err
}
}
result := make([]string, 0)
for k, _ := range fileMap {
result = append(result, k)
}
return result, nil
}

func GetDirsSomeFileMinio(bucket string, prefixRootPath string, relativePath string, marker string, pageSize int) ([]FileInfo, string, error) {
_, core, err := getClients()
if err != nil {
log.Error("getClients failed:", err.Error())
return nil, "", err
}

Prefix := prefixRootPath + relativePath
if !strings.HasSuffix(Prefix, "/") {
Prefix += "/"
}
log.Info("bucket=" + bucket + " Prefix=" + Prefix)
fileInfos := make([]FileInfo, 0)

fileMap := make(map[string]bool, 0)
index := 1
for {
output, err := core.ListObjects(bucket, Prefix, marker, "", 1000)
if err == nil {
log.Info("Page:%d\n", index)
index++
isBreak := false
for _, val := range output.Contents {
//log.Info("val key=" + val.Key)
var isDir bool
var fileName string
if val.Key == Prefix {
continue
}
fileNameRune := []rune(val.Key)
prefixRune := []rune(Prefix)

fileName = string(fileNameRune[len(prefixRune):])
files := strings.Split(fileName, "/")
if fileMap[files[0]] {
continue
} else {
fileMap[files[0]] = true
}
ParenDir := relativePath
fileName = files[0]
if len(files) > 1 {
isDir = true
ParenDir += fileName + "/"
} else {
isDir = false
}
fileInfo := FileInfo{
ModTime: val.LastModified.Local().Format("2006-01-02 15:04:05"),
FileName: fileName,
Size: val.Size,
IsDir: isDir,
ParenDir: ParenDir,
}
fileInfos = append(fileInfos, fileInfo)
if len(fileInfos) >= pageSize {
marker = val.Key
isBreak = true
break
}
}
if isBreak {
break
}
if output.IsTruncated {
marker = output.NextMarker
} else {
marker = ""
break
}
} else {
log.Error("Message:%s", err.Error())
return nil, "", err
}
}
return fileInfos, marker, err
}

+ 148
- 1
modules/storage/obs.go View File

@@ -742,7 +742,7 @@ func PutStringToObs(bucket, key string, fileContent string) error {
}

func PutReaderToObs(bucket, key string, reader io.Reader) error {
log.Info("PutStringToObs bucket=" + bucket + " key=" + key)
log.Info("PutReaderToObs bucket=" + bucket + " key=" + key)
input := &obs.PutObjectInput{}
input.Bucket = bucket
input.Key = key
@@ -755,3 +755,150 @@ func PutReaderToObs(bucket, key string, reader io.Reader) error {
}
return err
}

func GetDirsList(bucket string, prefixRootPath string, prefix string, dirLevel int) ([]string, error) {
input := &obs.ListObjectsInput{}
input.Bucket = bucket
input.Prefix = prefixRootPath + prefix
if !strings.HasSuffix(input.Prefix, "/") {
input.Prefix += "/"
}
prefixLen := len(input.Prefix)
fileMap := make(map[string]bool, 0)
index := 1
for {
output, err := ObsCli.ListObjects(input)
if err == nil {
log.Info("Page:%d\n input.Prefix=v%", index, input.Prefix)
log.Info("input.Prefix=" + input.Prefix)
index++
for _, val := range output.Contents {
fileName := val.Key[prefixLen:]
files := strings.Split(fileName, "/")
currentLevel := 0
for {
if currentLevel >= dirLevel || currentLevel >= (len(files)-1) {
break
}
path := getPathFromPathArrays(files, currentLevel)
if !fileMap[path] {
fileMap[path] = true
}
currentLevel = currentLevel + 1
}
}
if output.IsTruncated {
input.Marker = output.NextMarker
} else {
break
}
} else {
if obsError, ok := err.(obs.ObsError); ok {
log.Error("Code:%s, Message:%s", obsError.Code, obsError.Message)
}
return nil, err
}
}
result := make([]string, 0)
for k, _ := range fileMap {
result = append(result, k)
}
return result, nil
}

func getPathFromPathArrays(files []string, currentLevel int) string {
from := 0
re := ""
for {
re += files[from]
if from >= currentLevel {
break
}
from = from + 1
re += "/"
}
return re
}

func GetDirsSomeFile(bucket string, prefixRootPath string, prefix string, marker string, pageSize int) ([]FileInfo, string, error) {
input := &obs.ListObjectsInput{}
input.Bucket = bucket
input.Prefix = prefixRootPath + prefix
if !strings.HasSuffix(input.Prefix, "/") {
input.Prefix += "/"
}
input.Marker = marker
fileInfos := make([]FileInfo, 0)
//prefixLen := len(input.Prefix)
fileMap := make(map[string]bool, 0)
index := 1
for {
output, err := ObsCli.ListObjects(input)
if err == nil {
log.Info("Page:%d input.Prefix=v%", index, input.Prefix)
log.Info("input.Prefix=" + input.Prefix)
index++
isBreak := false
for _, val := range output.Contents {
var isDir bool
var fileName string
//log.Info("val.Key=" + val.Key)
if val.Key == input.Prefix {
continue
}
fileNameRune := []rune(val.Key)
prefixRune := []rune(input.Prefix)

fileName = string(fileNameRune[len(prefixRune):])
//log.Info("fileName=" + fileName)
//val.Key[prefixLen:]
files := strings.Split(fileName, "/")
if fileMap[files[0]] {
continue
} else {
fileMap[files[0]] = true
}
ParenDir := prefix
fileName = files[0]
if len(files) > 1 {
isDir = true
ParenDir += fileName + "/"
} else {
isDir = false
}
fileInfo := FileInfo{
ModTime: val.LastModified.Local().Format("2006-01-02 15:04:05"),
FileName: fileName,
Size: val.Size,
IsDir: isDir,
ParenDir: ParenDir,
}
fileInfos = append(fileInfos, fileInfo)
if len(fileInfos) >= pageSize {
marker = val.Key
log.Info("marker 1= " + marker)
isBreak = true
break
}
}
if isBreak {
break
}
if output.IsTruncated {
input.Marker = output.NextMarker
marker = output.NextMarker
log.Info("marker 2= " + marker)
} else {
marker = ""
log.Info("marker 3= " + marker)
break
}
} else {
if obsError, ok := err.(obs.ObsError); ok {
log.Error("Code:%s, Message:%s", obsError.Code, obsError.Message)
}
return nil, "", err
}
}
return fileInfos, marker, nil
}

+ 1
- 5
modules/urfs_client/objectstorage/mocks/objectstorage_mock.go View File

@@ -1,9 +1,5 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: objectstorage.go

// Package mocks is a generated GoMock package.
package mocks

import (
gomock "github.com/golang/mock/gomock"
reflect "reflect"
)

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

@@ -335,6 +335,7 @@ robot = Robot
federated_learning = Federated learning
data_mining = Data mining
RISC-V_development = RISC-V development
domestic_computing_power = Domestic computing power

[auth]
create_new_account = Register Account
@@ -864,6 +865,12 @@ download_copy=Copy URL
create_dataset_fail=Failed to create dataset.
query_dataset_fail=Failed to query dataset.
edit_attachment_fail=Failed to update description.
file_list=File list
file_not_support_preview=File does not support preview
please_select_file_preview=Please select a file for preview
see_more=See more
query_timeout_tips=The server is processing it. Drink a glass of water and come back to take a look~

show_dataset= Dataset
edit_dataset= Edit Dataset
update_dataset= Update Dataset
@@ -1002,6 +1009,7 @@ go_new_dataset= to create the dataset
export_tips = Only <span style="color:red">zip/tar.gz</span> type result file export is supported, and the exported file can finally be viewed on the Datasets tab of the current project.

[repo]
attachmentfilesizetobig=The file size exceeds 2000 lines or 2MB, and preview is not supported.
owner = Owner
repo_name = Repository Name
repo_name_helper = Good repository names use short, memorable and unique keywords.
@@ -2507,6 +2515,8 @@ imagetopic.format_prompt = Topics can be up to 35 characters long.
use_repo_agreement=I promise that the content of this warehouse does not violate any national laws and regulations. During the use of the warehouse, I will abide by the OpenI community management regulations and platform usage rules, and will not conduct malicious attacks, mining, or any other illegal or disruptive platform order. Information release and related behaviors. For more information please refer to
openi_use_agreement=OpenI Openi Community Platform Use Agreement.
reuse_last_result = Reuse last result
migratingData=Data migration in progress
centerPending=Queuing in sub centers
[org]
org_name_holder = Organization Name
org_full_name_holder = Organization Full Name
@@ -3469,6 +3479,8 @@ dataset_number_over_limit = The dataset count exceed the limit
result_cleared=The files of the task have been cleared, can not restart or retrain any more, please create a new task instead
model_not_exist=The model in the task does not exist or has been deleted
too_many_notebook=A user can have up to 5 debug tasks, please try again after delete some debug tasks.
can_not_stop_creating_job=AI task is creating, can not be stopped.
no_center_match=Can not match a AI center, please select other specification.

[common_error]
system_error = System error.Please try again later


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

@@ -338,6 +338,7 @@ robot = 机器人
federated_learning = 联邦学习
data_mining = 数据挖掘
RISC-V_development = RISC-V开发
domestic_computing_power = 国产算力

[auth]
create_new_account=注册帐号
@@ -864,6 +865,11 @@ create_dataset=创建数据集
create_dataset_fail=创建数据集失败。
query_dataset_fail=查询数据集失败。
edit_attachment_fail=修改描述失败。
file_list=文件列表
file_not_support_preview=文件暂不支持预览
please_select_file_preview=请选择文件进行预览
see_more=查看更多
query_timeout_tips=服务器正在处理,喝杯水回来再看看~

reference_dataset_fail=关联数据集失败,请稍后再试。
cancel_reference_dataset_fail=取消关联数据集失败,请稍后再试。
@@ -1007,6 +1013,7 @@ go_new_dataset=去创建数据集
export_tips = 仅支持 <span style="color:red">zip/tar.gz</span> 类型的结果文件导出,导出的文件最终可以在当前项目的数据集页签下查看。

[repo]
attachmentfilesizetobig=文件大小超过2000行或者超过2MB,不支持预览。
owner=拥有者
repo_name=项目名称
repo_name_helper=好的存储库名称使用简短、深刻和独特的关键字。
@@ -2525,6 +2532,9 @@ imagetopic.format_prompt=标签长度不得超过35个字符
use_repo_agreement=我承诺此仓内容不违反任何国家法律法规,仓库使用过程中遵守OpenI启智社区管理规定和平台使用规则,不进行恶意攻击、挖矿等任何违法或扰乱平台秩序的信息发布和相关行为。更多信息请参考
openi_use_agreement=OpenI启智社区平台使用协议
reuse_last_result = 复用上次结果
migratingData=数据迁移中
centerPending=分中心排队中

[org]
org_name_holder=组织名称
org_full_name_holder=组织全名
@@ -3492,6 +3502,8 @@ dataset_number_over_limit = 选择的数据集文件数量超出限制
result_cleared=源任务的文件已被清理,无法再次调试或复用训练结果,请新建任务。
model_not_exist=选择的预训练模型不存在或者已被删除
too_many_notebook=每个用户最多只能创建5个调试任务,请删除历史任务再新建。
can_not_stop_creating_job=任务正在创建中,请等创建完成后再尝试停止。
no_center_match=没有可分配的中心,请选择其他规格。


[common_error]


+ 1
- 0
public/img/domestic/ascend.svg View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="336" height="110" viewBox="0 0 84 28"><g fill="none" fill-rule="evenodd"><path d="M0 0h84v32H0z"/><path fill="#040000" fill-rule="nonzero" d="M69.4 13.3h-.95a3.04 3.04 0 0 0-3.03 3.01l-.04 5.75h1.5v-5.63a1.6 1.6 0 0 1 1.6-1.6l.78.01c.9.02 1.62.75 1.62 1.65v5.56h1.5v-5.77a2.98 2.98 0 0 0-2.98-2.98Zm10.81-2.95v3.62c-.7-.66-1.64-1.01-2.6-1a4.4 4.4 0 0 0-4.38 4.54 4.42 4.42 0 0 0 4.37 4.55c.97.02 1.9-.33 2.61-.97v.9h1.52V10.35H80.2Zm-2.6 4.14c1.75 0 2.55 1.57 2.55 3.02s-.8 3.01-2.56 3.01a2.92 2.92 0 0 1-2.87-3.01c0-1.7 1.26-3.03 2.87-3.03v.01Zm-34.4 2.24-.53-.11c-1.04-.22-1.42-.52-1.42-.96 0-.5.7-.87 1.43-.87s1.35.36 1.35.97v.3h1.78v-.3c0-1.53-1.27-2.45-3.13-2.45-1.76 0-3.2 1-3.2 2.35 0 1.24 1.01 2.04 2.76 2.42l.5.1c1.54.33 1.67.79 1.67 1.2 0 .71-.7 1.2-1.71 1.2S41 20 41 19.18v-.29h-1.77v.3c0 1.68 1.43 2.87 3.48 2.87s3.52-1.12 3.52-2.67c0-1.75-1.46-2.31-3.04-2.66Zm14.23 1.33.03.13c.27 1.4 1.34 2.34 2.68 2.34 1 0 1.74-.2 2.22-.6l.34-.3 1.1 1.09-.43.34c-.8.65-1.88.98-3.23.98-1.1.01-2.17-.4-2.98-1.15a4.18 4.18 0 0 1-1.25-2.66l-.02-.17h1.54Zm2.7-4.88a4.8 4.8 0 0 1 3.1 1.28c.89.82 1.37 2 1.31 3.2l-.03.72h-3.1v-1.5h1.5a2.89 2.89 0 0 0-2.78-2.17c-1.32 0-2.4.93-2.68 2.32l-.02.12H55.9l.03-.17a4.22 4.22 0 0 1 4.21-3.8Zm.14 3.75v1.34h-1.72v-1.34h1.72Zm-26.63-6.7-4.92 11.82h1.9l1.43-3.87h3.82l1.44 3.88h1.89l-4.72-11.81-.84-.01Zm1.65 6.39h-2.64l1.26-3.1a.09.09 0 0 1 .09-.05.1.1 0 0 1 .09.05l1.2 3.1ZM51.55 15c.75.05 1.43.4 1.9.99l.04.06h1.7l-.1-.22a4.09 4.09 0 0 0-3.54-2.29V15Zm-3.03 2.36a2.7 2.7 0 0 1 2.12-2.31v-1.48A4.06 4.06 0 0 0 47 17.36h1.51Zm5.07 2.02-.04.07a2.79 2.79 0 0 1-5.01-1.18h-1.51a4.1 4.1 0 0 0 4.24 3.78c1.81 0 3.28-.92 3.91-2.45l.09-.22h-1.68Z"/><path fill="#C31D20" fill-rule="nonzero" d="M21.29 2.2a1.22 1.22 0 0 1 2.1.75l.04 7.36c-3.8 1.38-8.23 4.4-12.58 9.3v.02l-6.6 7.36a1.91 1.91 0 1 1-2.86-2.54L17.97 5.78Zm-6.1 15.53c2.3-1.8 4.97-3.05 8.24-2.71l-.15 8.65a1.48 1.48 0 0 1-2.43 1.2Z"/></g></svg>

+ 1
- 0
public/img/domestic/cambricon.svg View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" id="_图层_2" data-name="图层 2" viewBox="0 0 115.29 39.51"><defs><style>.cls-1{fill:#0077ed;stroke-width:0}</style></defs><g id="_图层_1-2" data-name="图层 1"><path d="m70.22 19.95 2.46-1.71V7.3l-2.46-1.7v14.35zM2.47 2.47h10.25L14.42 0H1.2C.54 0 0 .54 0 1.2v17.04l2.47 1.7V2.47ZM36.27 19.95l2.47-1.71v-7.26l-2.47-1.7v10.67zM62.02 6.2h-.03c-.67 0-1.2.54-1.2 1.2v12.54l2.47-1.7V8.67h3.95l1.7-2.47h-6.88Z" class="cls-1"/><path d="M3.27 17.48v2.47h11.3l-1.7-2.47h-9.6zM74.19 7.43v10.81l2.47 1.7V8.68h8.4l1.7-2.47H75.39c-.67 0-1.2.54-1.2 1.2Z" class="cls-1"/><path d="M77.46 17.48v2.47h8.9l-1.7-2.47h-7.2zM5.43 35.92l.3-1.39 4.66 1.05-.3 1.38zM3.75 37.9l.31-1.38 7.19 1.6-.31 1.4z" class="cls-1"/><path d="M11.34 33.86h3.12l-.98-1.42h-3v-.83h2.15v-1.33h-2.15v-.94h2.69v-.82h1.41v-2.37c0-.37-.3-.67-.67-.67H8.07l-.48-.69H6.17l.48.69H.8c-.37 0-.67.3-.67.67v2.37h1.42v.82h2.74v.94H2.15v1.33h2.14v.83H.22l.98 1.42h1.88L0 36.14v1.77l5.47-4.06h4.64l-.41.65 5.38 3.39v-1.68l-3.74-2.36Zm-2.29-6.54v.69H6.21v1.33h2.84v.94H6.21v1.33h2.84v.83H5.72v-5.12H4.3v.69H1.56V26.9h11.6v1.11h-2.68v-.69H9.06ZM115.29 35.13l-1.42.98v.52a.9.9 0 0 1-.89.89h-4.48v-5.74h3.87v-1.42h-4.63c-.37 0-.67.3-.67.67v7.91h5.9a2.31 2.31 0 0 0 2.31-2.31v-1.51ZM106 29.88l-1.04-.97-.76.81-1.95.23 3.49-4.94H104l-3.62 5.14v1.46l2.33-.28-2.33 2.51v1.64l5.65-.56v-1.43l-3.73.37 3.7-3.98zM100.38 38.71l5.65-.5v-1.43l-5.65.5v1.43z" class="cls-1"/><path d="M112.87 26.71v6.33l1.42-.98v-6.31l-1.24-.46h-6.29l.99 1.42h5.12zM100.53 7.43v-.41l-2.15-.8h-9.22c-.67 0-1.2.54-1.2 1.2v10.82l2.47 1.7V8.68h7.64v6.6a2.2 2.2 0 0 1-2.2 2.2h-4.64v2.47h4.64a4.66 4.66 0 0 0 4.66-4.66V7.43ZM104.54 8.69h7.15v11.26l2.47-1.7V7.02l-2.15-.8h-8.73c-.67 0-1.2.54-1.2 1.2v12.52l2.47-1.7V8.68ZM72.68 3.33l-1.23-.46h-1.23v1.71l2.46 1.7V3.33zM31.36 6.21c-.67 0-1.2.54-1.2 1.2v12.53l2.47-1.7V8.67h10.11v11.27l2.47-1.7V7.01l-2.15-.8H31.37ZM17.37 6.25l1.7 2.47h7.12v6.57a2.2 2.2 0 0 1-2.2 2.2h-5.44v-2.65c0-.51.41-.92.92-.92h4.28l1.69-2.45-5.98-.01a3.4 3.4 0 0 0-3.39 3.38v5.12h7.91a4.66 4.66 0 0 0 4.66-4.66V7.02l-2.08-.77h-9.2ZM51.28 25.68h6.68v1.42h-6.68zM64.05 26.91l-1.9-1.7-.95 1.06 1.9 1.7.95-1.06zM61.7 30.24h3.33l-.98-1.43h-2.59l.24 1.43zM56.23 34.14h2.45v-1.43h-2.45v-.93l-1.42-.99v5.95l-1.76.2v-4.39l-1.42-.98h-.01v5.53l-1.65.18v1.44l10.04-1.14v-1.43l-3.78.43v-2.44z" class="cls-1"/><path d="M64.77 37.54h-1.62a.88.88 0 0 1-.88-.75l-1.06-6.55-.23-1.42-.65-3.99h-1.44l.65 3.99h-9.4l.98 1.42h8.65l1.1 6.78a2.3 2.3 0 0 0 2.28 1.94h2.59l-.98-1.42ZM59.28 15.29V7.08l-2.14-.8H49.9l1.7 2.47h5.22v6.54a2.2 2.2 0 0 1-2.2 2.2h-5.45V.46L47.94 0H46.7v19.95h7.92a4.66 4.66 0 0 0 4.66-4.66Z" class="cls-1"/></g></svg>

+ 1
- 0
public/img/domestic/enflame.svg View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" id="_图层_2" data-name="图层 2" width="336" height="110" viewBox="0 0 125.67 56.9"><defs><style>.cls-1{fill:#e73828;stroke-width:0}</style></defs><g id="_图层_1-2" data-name="图层 1"><path id="svg_24" d="M11.87 1.3c4.1 5.6-1.3 13.3-9.9 26.4-8.6 13.1 13.6 19.8 15 20.4s-10.7-5.9-8.2-13.8c2.6-7.9 8.9-12.7 10.1-18.7 1.2-6-11.2-19.9-7-14.3Z" class="cls-1" data-name="svg 24"/><path id="svg_24-2" d="M23.97 18.3c2.4 3.2-.7 7.6-5.7 15.2-4.2 6.3.4 10.7 2.4 12.2.4.3 2.2 1.5 2.2 1.5s-2.7-4.6-.7-9.9c1.7-4.5 5.1-7.3 5.8-10.7.7-3.6-6.4-11.6-4-8.3Z" class="cls-1" data-name="svg 24"/><path d="M31.77 20.6h9.8v3.1h-6.4v4.5h6.2v3.1h-6.2v4.3h6.4v3.1h-9.8V20.6ZM44.37 25.2h3v1.2c.5-.5 1.7-1.6 3.7-1.6 1.2 0 3 .5 4.1 1.9 1.3 1.5 1.3 3.8 1.3 4.8v7.4h-3.3v-6.7c0-1.1 0-4.4-2.8-4.4-.6 0-1.6.3-2.2 1.2-.6.8-.6 2.3-.6 3.4v6.5h-3.3V25.2h.1ZM59.37 28.1h-1.2v-2.9h1.2c.1-.9.2-2.6 1.6-3.8.8-.7 1.8-1.1 2.9-1.1h.9v3.2c-1.3 0-2 0-2.1 1.7h1.9v2.9h-1.9v10.8h-3.3V28.1ZM66.67 20.6h3.3v18.2h-3.3V20.6ZM86.37 38.8h-3v-1.7c-1 1.2-3.1 2.1-4.8 2.1-3.5 0-6.6-2.8-6.6-7.4 0-4.2 3.1-7.2 6.8-7.2 2.8 0 4.4 2 4.5 2.2v-1.7h3v13.7h.1Zm-7.1-11.1c-2.7 0-4.1 2.3-4.1 4.4 0 2.3 1.7 4.2 4.1 4.2s4-1.8 4-4.3c0-2.8-2.1-4.3-4-4.3ZM88.87 25.2h3v1.2c.3-.4 1.2-1.6 3.6-1.6.7 0 2.7.2 3.9 2.1a5 5 0 0 1 4.4-2.1c2.7 0 4 1.4 4.5 2.1s1 2 1 4v8h-3.3v-7.6c0-.8 0-3.5-2.6-3.5-.9 0-1.8.5-2.3 1.3-.5.7-.5 1.9-.5 2.8V39h-3.3v-7.6c0-1.9-.7-3.5-2.7-3.5-2.6 0-2.6 2.9-2.6 4.3V39h-3.3V25.2h.2ZM114.87 33.5c.1.9 1.4 2.8 3.8 2.8 1.5 0 2.5-.6 3.1-1.7h3.4c-.8 2.5-3.4 4.7-6.6 4.7-4.2 0-7.2-3.2-7.2-7.2s2.9-7.3 7.2-7.3 7.1 3.7 7.1 7.1c0 .6-.1 1.2-.2 1.6h-10.6Zm7.4-2.6c-.4-2.2-1.9-3.1-3.7-3.1-1.3 0-3.2.6-3.9 3.1h7.6ZM37.77 47c0 1.2-.2 2.7-.6 3.7l-.8-.4c.4-.8.6-2.3.6-3.4l.8.1Zm2.1 8.1c-.2-.4-.6-1.2-1-1.8-.3 1.3-.8 2.5-1.8 3.5-.2-.3-.6-.7-.8-.8 1.6-1.9 1.8-4.4 1.8-6.9v-4.9h1.1v5.2c.3-.8.6-2 .7-2.9l1 .3c-.4 1-.7 2.1-1 2.9l-.7-.3c0 .8 0 1.6-.1 2.4.4.5 1.4 2 1.6 2.4l-.8.9Zm2.7-.7c.3.1.5.4.9.6.7.4 1.5.6 2.7.6.9 0 2.4-.1 3.3-.2-.1.3-.3.9-.3 1.2-.8 0-2.2.1-3.1.1-1.2 0-2.1-.2-2.8-.7-.5-.3-.9-.7-1.1-.7-.4 0-.9.8-1.3 1.6l-.9-1.1c.5-.6 1-1 1.5-1.3v-4.7h-1v-1h2.1v5.6Zm-1-6.6c-.2-.7-.6-1.7-.9-2.5l1-.3c.4.8.8 1.8 1 2.4l-1.1.4Zm7.1 5.8c-.2-.5-.7-1.2-1.2-1.8.1 1.3-.1 2.4-.4 2.9-.3.4-.7.6-1.2.6h-.8c0-.3-.1-.8-.3-1.1.3 0 .6.1.8.1s.4 0 .5-.3c.2-.3.3-.9.3-1.8-.9.8-2 1.6-3 2-.2-.3-.5-.6-.7-.8a9.9 9.9 0 0 0 3.6-2.4c0-.2-.1-.5-.2-.7-.7.6-1.7 1.3-2.4 1.6-.2-.2-.5-.6-.7-.8.9-.4 2.1-1.1 2.8-1.7-.1-.2-.3-.4-.4-.7-.6.4-1.2.8-1.7 1.1-.2-.2-.5-.6-.8-.8.9-.4 1.9-1 2.6-1.7h-2.3v-1h1.6c-.2-.5-.6-1.3-1-1.8l1-.4c.4.6.9 1.4 1.1 1.9l-.6.3h1.5c.4-.7.8-1.5 1-2.2l1.1.3c-.3.6-.7 1.3-1 1.9h1.6v1h-2.6c-.2.3-.5.6-.7.8.4.4.7.8.9 1.3.5-.5 1-1.2 1.4-1.6l.9.6c-.6.6-1.2 1.3-1.8 1.7.8.9 1.7 2.1 2.1 2.9l-1 .6ZM62.77 48.7c0 2.3-.2 5.6-1.5 7.8-.2-.2-.8-.5-1.1-.7 1.2-2.1 1.3-5.1 1.3-7.2v-4h11.5v1.2h-10.2v2.9Zm3.3 4.6c-.7 1-1.7 2.2-2.5 3l-1.1-.7c.8-.7 1.7-1.7 2.3-2.6l1.3.3Zm2.5-.9v3.1c0 .6-.1 1-.6 1.1-.5.2-1.2.2-2.2.2-.1-.3-.2-.8-.4-1.1h1.6c.2 0 .3-.1.3-.2v-3.1h-3.4v-5.2h2.7c.2-.4.4-.8.5-1.2l1.6.2-.6.9h4v5.2h-3.5v.1Zm-3.4-3.1h5.4v-1.1h-5.4v1.1Zm0 2.1h5.4v-1.1h-5.4v1.1Zm5.4 1.5c.8.9 1.9 2 2.5 2.8l-1.1.7c-.5-.7-1.6-2-2.4-2.9l1-.6ZM88.77 52.6c-.2-.4-.7-1.2-1.1-1.8v6.1h-1.3v-5.6c-.5 1.3-1.2 2.5-1.8 3.2-.1-.3-.4-.9-.6-1.2.8-.9 1.7-2.6 2.3-4.1h-2.1V48h2.3v-1.9l-1.8.3c0-.3-.2-.7-.4-1a33 33 0 0 0 4.5-1.1l.8 1.1c-.5.2-1.2.4-1.8.5V48h2v1.2h-2v.2c.4.4 1.6 1.9 1.9 2.2l-.9 1Zm6.7.7v3.6h-1.3v-3.3l-4.5.7-.2-1.3 4.7-.8V44h1.3v8l1.5-.3.2 1.2-1.7.4Zm-3.1-1.9c-.5-.6-1.5-1.5-2.4-2.1l.8-.8c.9.6 1.9 1.4 2.4 2l-.8.9Zm.3-3.7c-.4-.6-1.4-1.4-2.2-2l.9-.7c.8.5 1.8 1.4 2.3 1.9l-1 .8ZM112.77 51.2c-.5.2-1.1.3-1.6.5v3.7c0 .7-.1 1-.6 1.2-.4.2-1.1.2-2 .2-.1-.3-.2-.8-.4-1.2h1.4c.2 0 .3-.1.3-.3V52c-.6.2-1.1.3-1.6.4l-.3-1.2c.5-.1 1.2-.3 1.9-.4V48h-1.7v-1.2h1.7v-2.7h1.3v2.7h1.5V48h-1.5v2.5l1.5-.4.1 1.1Zm7.6-1.7c-.6 1.9-1.5 3.4-2.8 4.6 1 .7 2.1 1.3 3.5 1.6-.3.3-.7.8-.9 1.1-1.4-.4-2.6-1-3.7-1.9-1.1.8-2.5 1.4-3.9 1.9-.1-.3-.5-.9-.7-1.2 1.3-.3 2.6-.8 3.7-1.6-.9-1-1.7-2.2-2.2-3.6l.2-.1h-.6v-1.2h2.9v-1.9h-3.2V46h3.2v-2.1h1.3V46h3.3v1.2h-3.3v1.9h2.2l1 .4Zm-5.6.9c.5 1.1 1.1 2 1.9 2.9.9-.8 1.6-1.8 2.1-2.9h-4Z" class="cls-1"/></g></svg>

BIN
public/img/domestic/hygon.png View File

Before After
Width: 226  |  Height: 46  |  Size: 2.8 KiB

+ 1
- 0
public/img/domestic/iluvatar.svg
File diff suppressed because it is too large
View File


+ 1
- 0
public/img/domestic/metax.svg View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 362.76 87.74"><defs><style>.cls-1{fill:#040000}</style></defs><g id="图层_2" data-name="图层 2"><g id="图层_1-2" data-name="图层 1"><path d="M301.27 87.74 278.65 65.2l9.28-9.28 31.9 31.82h-18.56zM198.23 39.86l4.35-13.56h-55.82v13.56h18.71v47.88h14.05V39.86h18.71z" class="cls-1"/><path d="m239.42 25.88 24.81 24.89-36.98 36.97h18.56l36.98-36.97-24.82-24.89h-18.55z" style="fill:#4ab134"/><path d="m315.01 0-36.36 36.36 9.28 9.28L333.57 0h-18.56z" style="fill:#5c246a"/><path d="M339.38 40.58a28.48 28.48 0 0 0-5.81-3.25l1.94-2.77a33.14 33.14 0 0 1 5.93 3Zm2.86 4.09a117.2 117.2 0 0 1-5.2 9.83l-3.16-2.36a79.87 79.87 0 0 0 5.56-9.8Zm-1.14-12.26a34.33 34.33 0 0 0-5.69-3.41l2-2.7a34.05 34.05 0 0 1 5.81 3.13Zm14.07 4c1.63 4.54 4.49 9.15 7.59 11.76a14.68 14.68 0 0 0-2.7 3 31.33 31.33 0 0 1-6.24-9.83v13.47h-3.72V41.6a27.94 27.94 0 0 1-6.73 9.8 18.25 18.25 0 0 0-2.64-2.92c3.44-2.55 6.39-7.31 8-12.1h-6.42v-3.6h7.74v-6.42h3.72v6.42h8.05v3.6ZM361.64 76.84a21.73 21.73 0 0 1-3.87 5.74c.49 1.08 1 1.69 1.5 1.69s.65-1 .74-3a5.39 5.39 0 0 0 2.15 1.32c-.4 3.47-1.29 4.36-3.13 4.36-1.26 0-2.34-.89-3.26-2.42a19.21 19.21 0 0 1-2.73 2 12.86 12.86 0 0 0-1.66-1.78 3.45 3.45 0 0 1-.71 1.54 2.31 2.31 0 0 1-1.54.64 20.79 20.79 0 0 1-2.39 0 4.72 4.72 0 0 0-.59-2A15.23 15.23 0 0 0 348 85a.8.8 0 0 0 .67-.22 2.58 2.58 0 0 0 .46-1.26h-5.8a29.79 29.79 0 0 0 .92-2.92h-1.57v-2h.52a13 13 0 0 0-1.26-1.39v4.12H337v2.49h-2.86V60.55h7.77V77a15.23 15.23 0 0 0 3.32-1.78h-2.73v-2.1h4.08v-.77c-1.13.06-2.21.09-3.25.09a7.74 7.74 0 0 0-.56-1.66 59.63 59.63 0 0 0 8.36-.86l1.41 1.69c-1 .22-2.21.4-3.5.55v1h4a84.4 84.4 0 0 1-.15-2.89h2.86c0 1 .06 2 .12 2.89h2.92a18.82 18.82 0 0 0-2.64-1.85l1.5-1.44h-15.12v-2.19h7.8v-1.05H344v-2h6.33v-1h-7.07v-2.22h3.29a15.78 15.78 0 0 0-1.2-2.09l2.68-1a10.09 10.09 0 0 1 1.66 2.58l-1.39.55h5.47a18.51 18.51 0 0 0 1.54-3l3.35.83c-.46.74-1 1.5-1.48 2.21h3.72v2.15h-7.28v1h6.73v2h-6.73v1.05h8.2v2.15h-3.68a16.85 16.85 0 0 1 3 2.06L360 73.12h1.66v2.12h-5.59a32.45 32.45 0 0 0 .76 4.36 19.11 19.11 0 0 0 2.55-4.12ZM337 69.34h2v-5.59h-2Zm2 3.16h-2v5.66h2Zm12.81 9.07s0 .61-.09 1c-.07.58-.16 1.1-.25 1.57a17.87 17.87 0 0 0 3.1-2.22 36.34 36.34 0 0 1-1.38-6.63h-3.29c1 .49 2.37 1.16 2.83 1.44l-1.32 1.72a26.82 26.82 0 0 0-2.41-1.77v1.69h-2.46v-1.63a18.06 18.06 0 0 1-2.67 1.88h8.91v2h-6.11l-.25 1ZM14.21 87.74H0L26.32 26.3h20.67v44.47L58.64 26.3h23v61.44H67.37l1.37-47.41-11.82 47.41H33.56V40.33L14.21 87.74zM88.9 74.18h50.61v13.56H88.9zM88.9 26.3h22.39v13.56H88.9zM117.11 26.3h22.39v13.56h-22.39zM111.28 50.02l-22.38-.01v13.57l22.38-.01V50.02zM117.11 50.02v13.55l22.39-.01V50.02h-22.39zM220.62 26.3h-10.77L184.4 87.74h14.21l4.26-10.86h24.89l9.85-9.83Zm-5.06 18.14 7.26 18.87h-14.73Z" class="cls-1"/></g></g></svg>

+ 306
- 720
public/self/dataset_preview.js View File

@@ -1,754 +1,340 @@
var img=new Image();

var ip = getIp();



var token = getCookie("_csrf");

canvas = document.getElementById("myCanvas");
context = canvas.getContext("2d");
// canvas.width = document.getElementById("myCanvas").offsetWidth;
// canvas.height = document.getElementById("myCanvas").offsetWidth/1280*720;

canvas.width = document.getElementById("win_canvas").offsetWidth;
canvas.height = document.getElementById("win_canvas").offsetHeight;




var color_dict = {"car":"#0099CC", "person":"#FF99CC","point":"#00cc00","pointselected":"red"};
var color_person = {"0":"#13c90c","1":"#fc0707","2":"#FF99CC","3":"#fceb07"};

var rects=[];
var masks=[];
var pointShapes =[];

var fileindex =0;
var lastindex=false;
var labeltastresult;
(function () {
function DatasetPreview() {
this.ajaxTimeOut = 1000 * 60;
this.datasetData = DATASET_DATA;
this.supportImgReg = /(\.jpg|\.jpeg|\.png|\.gif|\.bmp)$/i;
this.supportTxtReg = /(\.txt|\.xml|\.html|\.json|\.py|\.sh|\.md|\.csv|\.log|\.js|\.css|\.ipynb)$/i;
this.data = {
filePath: [{ path: '', name: this.datasetData.path[0], ParenDir: '', marker: '' }],
dirMarkerChildrenMap: {},
fileContentMap: {},
currentPage: '',
};
this.currentFileList = [];
this.currentFile = '';
this.pageSize = 100;
this.getPathChildren();
this.eventInit();
}

var pageSize = 12;
var tableData;
var tablePageData;
var dataset_id = $('#hide_uuidid').val();
var dbdatasetid = dataset_id;
var textContent;
var labelInfo;
DatasetPreview.prototype.renderFilePath = function () {
var container = $('#file_path_container').empty();
var filePath = this.data.filePath;
for (let i = 0, iLen = filePath.length; i < iLen; i++) {
var path = filePath[i];
var pathEle;
if (i == iLen - 1) {
pathEle = $(`<div>
<span class="" href="javascript:;">${path.name}</span><div class="divider"> / </div>
</div>`);
} else {
pathEle = $(`<div>
<a class="section" href="javascript:;">${path.name}</a><div class="divider"> / </div>
</div>`);
}
pathEle.data('data', path);
container.append(pathEle);
}
};

page(0,pageSize);
DatasetPreview.prototype.prevDirs = function () {
this.data.filePath.pop();
this.getPathChildren();
};

DatasetPreview.prototype.nextDirs = function (pathObj) {
this.data.filePath.push({
...pathObj,
path: pathObj.FileName,
name: pathObj.FileName,
});
this.getPathChildren();
};

function getCookie(name)
{
var arr,reg=new RegExp("(^| )"+name+"=([^;]*)(;|$)");
if(arr=document.cookie.match(reg))
return unescape(arr[2]);
else
return null;
}
DatasetPreview.prototype.showGetPathChildrenTimeout = function () {
$('#myCanvas_div .tabpannel.ui.form .query-timeout').show();
$('#filelist').hide();
}

function list(current,pageSize){
$.ajax({
type:"GET",
url:ip + "/gitea-dateset-item-page",
headers: {
authorization:token,
},
dataType:"json",
data:{
'datasetId':dbdatasetid,
'startPage':current,
'pageSize':pageSize},
async:false,
success:function(json){
tablePageData = json;
tableData = json.data;
labeltastresult = tableData;
fileindex=0;
if(lastindex){
fileindex = pageSize - 1;
}
},
error:function(response) {
DatasetPreview.prototype.getPathChildrenMore = function () {
var self = this;
var lastDir = this.data.filePath[this.data.filePath.length - 1];
var path = this.data.filePath.map((item) => item.path).join('/');
if (!lastDir) return;
$('#myCanvas_div .tabpannel.ui.form').addClass('loading');
$.ajax({
type: "get",
url: `/api/v1/attachments/get_dir`,
dataType: "json",
timeout: this.ajaxTimeOut,
data: {
_csrf: this.datasetData.csrf,
uuid: this.datasetData.uuid,
marker: lastDir.marker,
pageSize: this.pageSize,
prefix: lastDir.ParenDir ? '/' + lastDir.ParenDir.replace(/^\//, '') : '',
},
success: function (res) {
$('#myCanvas_div .tabpannel.ui.form').removeClass('loading');
if (res.result_code == 0) {
var result = res.data.sort((a, b) => {
var a1 = a.IsDir ? 1 : 0;
var b1 = b.IsDir ? 1 : 0;
return b1 - a1;
});
var fileList = [];
for (let i = 0, iLen = result.length; i < iLen; i++) {
const file = result[i];
if (self.currentFileList.findIndex(itm => `${itm.ParenDir}${itm.FileName}` == `${file.ParenDir}${file.FileName}`) >= 0) {
continue;
}
fileList.push(file);
}
self.data.dirMarkerChildrenMap[path + '-' + lastDir.marker] = result;
self.currentFileList = self.currentFileList.concat(fileList);
lastDir.marker = res.marker;
self.renderFileListAdd(fileList, result.length);
} else {
console.log(res);
}
});
}


},
error: function (err) {
$('#myCanvas_div .tabpannel.ui.form').removeClass('loading');
console.log(err);
if (err.statusText == 'timeout') {
self.showGetPathChildrenTimeout();
}
}
});
}

function getTextContent(uuid,filename){
$.ajax({
type:"GET",
url:ip + "/getgiteatext",
headers: {
authorization:token,
},
dataType:"text",
data:{
'uuid':uuid,
'filename':filename
},
async:false,
success:function(json){
textContent = json;
DatasetPreview.prototype.getPathChildren = function () {
this.renderFilePath();
var lastDir = this.data.filePath[this.data.filePath.length - 1];
if (!lastDir) return;
var path = this.data.filePath.map((item) => item.path).join('/');
var cache = this.data.dirMarkerChildrenMap[path + '-' + lastDir.marker];
var self = this;
if (false && cache) {
self.currentFileList = cache;
this.renderFileList(cache);
} else {
$('#myCanvas_div .tabpannel.ui.form').addClass('loading');
$.ajax({
type: "get",
url: `/api/v1/attachments/get_dir`,
dataType: "json",
timeout: this.ajaxTimeOut,
data: {
_csrf: this.datasetData.csrf,
uuid: this.datasetData.uuid,
marker: '',
pageSize: this.pageSize,
prefix: lastDir.ParenDir ? '/' + lastDir.ParenDir.replace(/^\//, '') : '',
},
success: function (res) {
$('#myCanvas_div .tabpannel.ui.form').removeClass('loading');
if (res.result_code == 0) {
var result = res.data.sort((a, b) => {
var a1 = a.IsDir ? 1 : 0;
var b1 = b.IsDir ? 1 : 0;
return b1 - a1;
});
self.data.dirMarkerChildrenMap[path + '-' + lastDir.marker] = result;
lastDir.marker = res.marker;
self.currentFileList = result;
self.currentFile = '';
self.renderFileList(result);
} else {
console.log(res);
}
},
error:function(response) {
error: function (err) {
$('#myCanvas_div .tabpannel.ui.form').removeClass('loading');
console.log(err);
if (err.statusText == 'timeout') {
self.showGetPathChildrenTimeout();
}
}
});
}



/*
function previewDataSetFile(uuid,filename){
console.log('uuid=' + uuid + " filename=" + filename);
loadimg(uuid,filename);
}

function loadimg(uuid,filename){
img.src = ip + "/getgiteaimage?uuid=" + uuid + "&filename=" + filename;
var fname = filename.substring(filename.lastIndexOf('/') + 1);
$("#filename").text(fname);
}
*/

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

}
}
var fname = tableData[fileindex].pic_image_field.substring(tableData[fileindex].pic_image_field.lastIndexOf('/') + 1);
$("#filename").text(fname);
}

img.onload = function(){

canvas.width = document.getElementById("win_canvas").offsetWidth;
canvas.height = document.getElementById("win_canvas").offsetHeight-40;
//调整画布大小
// if ((img.width/img.height)<(canvas.width/canvas.height)){
// canvas.width=canvas.height * img.width / img.height;
// }
// else{
// canvas.height=canvas.width * img.height / img.width;
// }
drawimage();
}

function isEmpty(str){
if(typeof str == "undefined" || str == null || str == ""){
return true;
}
return false;
}
function drawimage() {
parse_labelinfo(labeltastresult[fileindex].label_info);
// 清除画布,准备绘制
context.clearRect(0, 0, canvas.width, canvas.heigth);
// modal_context.cleararc
context.drawImage(img,0,0,img.width,img.height,0,0,canvas.width, canvas.height);
for(var i=0; i<rects.length; i++) {
var rect = rects[i];
rectxywh = new Array(4);
rectxywh_tmp = rect.getXYWH();
rectxywh[0] = rectxywh_tmp[0] / canvas.width * canvas.width;
rectxywh[1] = rectxywh_tmp[1] / canvas.height * canvas.height;
rectxywh[2] = rectxywh_tmp[2] / canvas.width * canvas.width;
rectxywh[3] = rectxywh_tmp[3] / canvas.height * canvas.height;
// 绘制矩形

context.lineWidth = 3;
if(rect.type == "person"){
context.strokeStyle = color_person[ i % 4];
}else{
context.strokeStyle=color_dict[rect.type];
}
context.strokeRect(rectxywh[0],rectxywh[1],rectxywh[2],rectxywh[3]);
context.font = "15px Georgia";
context.fillStyle= context.strokeStyle;

context.fillText(rect.type, rectxywh[0],rectxywh[1]-5);
for(var j=0; j<4; j++){
var p_tmp = rect.points[j];
var p = new point(0,0);
p.x = p_tmp.x/ canvas.width * canvas.width;;
p.y = p_tmp.y / canvas.height * canvas.height;
context.fillStyle = color_dict["point"];
context.fillRect(p.x-2,p.y-2,4,4);
}
}
for (var i=0; i<masks.length; i++){
context.strokeStyle="purple"
var mask =masks[i];
context.lineWidth = 2;
for (var j=1; j<mask.points.length; j++){
context.beginPath();
context.moveTo(mask.points[j-1].x, mask.points[j-1].y);
context.lineTo(mask.points[j].x,mask.points[j].y);
context.stroke();
// modal_context.closePath();
}
context.moveTo(mask.points[mask.points.length-1].x,mask.points[mask.points.length-1].y);
context.lineTo(mask.points[0].x,mask.points[0].y);
context.stroke();
context.closePath();
for (var j=0; j<mask.points.length; j++){
var p = mask.points[j]
context.fillStyle = color_dict["point"];
context.fillRect(p.x-2,p.y-2,4,4);
}
}
}
function parse_labelinfo(labelinfo){
rects.length = 0;
masks.length = 0;
pointShapes.length = 0;
if(!isEmpty(labelinfo)){
var label_arr = JSON.parse(labelinfo);
for(var i=0;i<label_arr.length;i++){
if(!isEmpty(label_arr[i].mask)){
cls=label_arr[i].class_name;
var tmpMask = new maskar(getCanvasLocationX(label_arr[i].mask[0]),getCanvasLocationY(label_arr[i].mask[1]),cls);
for(var j = 2; j < label_arr[i].mask.length; j+=2){
tmpMask.points.push(new point(getCanvasLocationX(label_arr[i].mask[j]),getCanvasLocationY(label_arr[i].mask[j+1])));
}
if(!isEmpty(label_arr[i].id)){
tmpMask.id= label_arr[i].id;
}
if(!isEmpty(label_arr[i].blurred)){
tmpMask.blurred = label_arr[i].blurred;
}
if(!isEmpty(label_arr[i].goodIllumination)){
tmpMask.goodIllumination = label_arr[i].goodIllumination;
}
if(!isEmpty(label_arr[i].frontview)){
tmpMask.frontview = label_arr[i].frontview;
}
tmpMask.finish = true;
masks.push(tmpMask);
}else if(!isEmpty(label_arr[i].box)){
x1 = getCanvasLocationX(label_arr[i].box[0]);
y1 = getCanvasLocationY(label_arr[i].box[1]);
x2 = getCanvasLocationX(label_arr[i].box[2]);
y2 = getCanvasLocationY(label_arr[i].box[3]);
cls=label_arr[i].class_name;
score = label_arr[i].score;
rect = new rectar(x1,y1,x2,y2,cls,score);
if(!isEmpty(label_arr[i].id)){
rect.id= label_arr[i].id;
}
if(!isEmpty(label_arr[i].blurred)){
rect.blurred = label_arr[i].blurred;
}
if(!isEmpty(label_arr[i].goodIllumination)){
rect.goodIllumination = label_arr[i].goodIllumination;
}
if(!isEmpty(label_arr[i].frontview)){
rect.frontview = label_arr[i].frontview;
}
rects.push(rect);
}else if(!isEmpty(label_arr[i].keypoints)){
cls=label_arr[i].class_name;
score = label_arr[i].score;
var pointShapeObj = new pointShape(getCanvasLocationX(label_arr[i].keypoints[0]),getCanvasLocationY(label_arr[i].keypoints[1]),cls,score);
pointShapes.push(pointShapeObj);
}
}
}
}

function point(x,y){
this.x = x;
this.y = y;
this.isSelected = false;
};

function pointShape(x,y,type,score=1.0){
this.x = x;
this.y = y;
this.isSelected = false;
this.type = type;
this.score = score;
this.id =""; //标识
this.blurred=false;//模糊不清的; 记不清的; 难以区分的; 模棱两可的
this.goodIllumination = false; //照明
this.frontview = false;//正面图
}

function rectar(x1,y1,x2,y2, type, score=1.0){
// this.x = x;
// this.y = y;
// this.width = width;
// this.height = height;
this.type = type;
this.score = score;
//0--1,
//| |
//2--3
this.points = [new point(x1,y1), new point(x1, y2),new point(x2, y1),new point(x2, y2)];
this.getXYWH = function(){
var x_min=Math.min(this.points[0].x,this.points[1].x,this.points[2].x,this.points[3].x);
var x_max=Math.max(this.points[0].x,this.points[1].x,this.points[2].x,this.points[3].x);
var y_min=Math.min(this.points[0].y,this.points[1].y,this.points[2].y,this.points[3].y);
var y_max=Math.max(this.points[0].y,this.points[1].y,this.points[2].y,this.points[3].y);
return [x_min,y_min,x_max-x_min,y_max-y_min];
});
}
this.getX1Y1X2Y2 = function(){
var x_min=Math.min(this.points[0].x,this.points[1].x,this.points[2].x,this.points[3].x);
var x_max=Math.max(this.points[0].x,this.points[1].x,this.points[2].x,this.points[3].x);
var y_min=Math.min(this.points[0].y,this.points[1].y,this.points[2].y,this.points[3].y);
var y_max=Math.max(this.points[0].y,this.points[1].y,this.points[2].y,this.points[3].y);
return [x_min,y_min,x_max,y_max];
}
this.getdiapid = function(pid){//获取对角点
var twooverlapped,fouroverlapped;
for (var i=0;i<4;i++){
if ((this.points[pid].x!=this.points[i].x)&&(this.points[pid].y!=this.points[i].y)){
return i;
}
if ((this.points[pid].x!=this.points[i].x)||(this.points[pid].y!=this.points[i].y)){
twooverlapped=i;
}
if (i!=pid) fouroverlapped=i;
};

}
if (twooverlapped)
return twooverlapped;
return fouroverlapped;
DatasetPreview.prototype.renderFileListAdd = function (files, length) {
var domC = $('#filelist');
domC.find('.file-more').remove();
for (let i = 0, iLen = files.length; i < iLen; i++) {
const file = files[i];
const fileEl = $(`<div class="file-item" title="${file.FileName}">
<i width="16" height="16" aria-hidden="true" style="color: ${file.IsDir ? 'rgb(91, 185, 115);' : ''}" class="icon ${file.IsDir ? 'folder outline' : 'file alternate outline'}"></i>
<span>${file.FileName}</span>
</div>`);
fileEl.data('data', file);
domC.append(fileEl);
}
this.mouseonpoint = false;
this.mouseonrect = false;
this.isSelected = false;
this.id =""; //标识
this.blurred=false;//模糊不清的; 记不清的; 难以区分的; 模棱两可的
this.goodIllumination = true; //照明
this.frontview = true;//正面图
};



function maskar(x0,y0,type){
this.type = type;
this.points = [new point(x0,y0)];
this.finish = false;
this.mouseonpoint = false;
this.mouseonmask = false;
this.isSelected = false;
this.getX1Y1 = function(){return [this.points[0].x,this.points[0].y]}
this.getBound = function(){
mlen = this.points.length;
var minX = 999999999, minY = 999999999, maxX = -1, maxY = -1;
for (var i = 0; i < mlen; i ++){
if(minX > this.points[i].x){
minX = this.points[i].x;
}
if(maxX < this.points[i].x){
maxX = this.points[i].x;
}
if(minY > this.points[i].y){
minY = this.points[i].y;
}
if(maxY < this.points[i].y){
maxY = this.points[i].y;
}
var lastDir = this.data.filePath[this.data.filePath.length - 1];
if (!lastDir) return;
if (length >= this.pageSize && lastDir.marker) {
domC.append(`<div class="file-more">${$('#lang-seemore').text()}</div>`);
}
return [minX, minY, maxX, maxY];
}
this.id =""; //标识
this.blurred=false;//模糊不清的; 记不清的; 难以区分的; 模棱两可的
this.goodIllumination = true; //照明
this.frontview = true;//正面图
}

function getCanvasLocationX(num){
return Math.round(num * canvas.width/parseInt(img.width));
}

function getCanvasLocationY(num){
return Math.round(num * canvas.height/parseInt(img.height));
}


function page(current,pageSize){
list(current,pageSize);
showfilelist();
breadFiles();
loadimg();
setPage(tablePageData,pageSize);
}


getLabelInfo(dataset_id);
showlabelflist();


function nextPage(){
var current = $('#displayPage1').text();
page(current,pageSize);
}

function prePage(){
var current =$('#displayPage1').text();
if(current > 1){
page(current - 2,pageSize);
}
}

function goPage(){
var goNum = $('#goNum').val();
};

var pageTotal = $("#totalNum").text();
var pageNum = parseInt(pageTotal/pageSize);
if(pageTotal%pageSize!=0){
pageNum += 1;
}else {
pageNum = pageNum;
DatasetPreview.prototype.renderFileList = function (files) {
var domC = $('#filelist').empty();
var findFile = false;
for (let i = 0, iLen = files.length; i < iLen; i++) {
const file = files[i];
const fileEl = $(`<div class="file-item" title="${file.FileName}">
<i width="16" height="16" aria-hidden="true" style="color: ${file.IsDir ? 'rgb(91, 185, 115);' : ''}" class="icon ${file.IsDir ? 'folder outline' : 'file alternate outline'}"></i>
<span>${file.FileName}</span>
</div>`);
fileEl.data('data', file);
domC.append(fileEl);
}
if (goNum<=0){
alert("请输入大于0的数值");
if (!findFile) {
this.currentFile = null;
this.renderPleseSelectFile();
}
else if(goNum<=pageNum){
page(goNum - 1,pageSize);
var lastDir = this.data.filePath[this.data.filePath.length - 1];
if (!lastDir) return;
if (files.length >= this.pageSize && lastDir.marker) {
domC.append(`<div class="file-more">${$('#lang-seemore').text()}</div>`);
}
else{
alert("不能超出总页码!");
}
}
};

$("#goNum").keydown(function (e) {
if (e.keyCode == 13) {
goPage();
DatasetPreview.prototype.renderPreview = function (file) {
var fileName = file.FileName;
if (this.supportImgReg.test(fileName)) {
console.log('renderImage');
$('#textcontent').hide();
$('#win_canvas .select-file').hide();
$('#win_canvas .not-support').hide();
$('#imgcontent').attr('src', `/api/v1/attachments/get_image_content?uuid=${this.datasetData.uuid}&filePath=${file.ParenDir + file.FileName}&type=${this.datasetData.type}&_csrf=${this.datasetData.csrf}`).show();
} else if (this.supportTxtReg.test(fileName)) {
console.log('getFileText');
this.getFileText(file);
} else {
console.log('not support');
this.renderNotSupport();
}
});

function setPage(pageData,pageSize){
if (isEmpty(pageData)){
return;
}
var startIndex = pageData.current * pageSize;
if(pageData.total > 0){
startIndex = startIndex + 1;
}
if(startIndex < 10){
$('#startIndex').text(" " + (startIndex));
}else{
$('#startIndex').text(startIndex);
}
var endIndex = pageData.current * pageSize + pageData.data.length;
if(endIndex < 10){
$('#endIndex').text(" " + (endIndex));
}else{
$('#endIndex').text(endIndex);
}
$('#totalNum').text(pageData.total);
$('#displayPage1').text(pageData.current + 1);


if(pageData.current == 0){
$('#prePage').removeAttr("href");
$('#prePage').attr('style','color:#f5f5f6;');
}
else{
$('#prePage').attr("href","javascript:prePage()");
$('#prePage').attr('style','color:#000;');
}

if((pageData.current + 1) * pageSize >= pageData.total){
$('#nextPage').removeAttr("href");
$('#nextPage').attr('style','color:#f5f5f6;')
}
else{
$('#nextPage').attr("href","javascript:nextPage()");
$('#nextPage').attr('style','color:#000;');
}
};

var pageTotal = pageData.total;
var pageNum = parseInt(pageTotal/pageSize);
if(pageTotal%pageSize!=0){
pageNum += 1;
}else {
pageNum = pageNum;
DatasetPreview.prototype.renderNotSupport = function () {
$('#imgcontent').hide();
$('#textcontent').hide();
$('#win_canvas .select-file').hide();
$('#win_canvas .not-support').show();
}
$("#totalPageNum").text(pageNum);
}

function clickfilelist(index){
fileindex=index;
loadimg();
//drawimage();
breadFiles()
showfilelist();
}

function clickNext(){
if(fileindex<tableData.length-1) {
next();
}else{
if((tablePageData.current + 1) * pageSize >= tablePageData.total){
return;
}
nextPage();
DatasetPreview.prototype.renderPleseSelectFile = function () {
$('#imgcontent').hide();
$('#textcontent').hide();
$('#win_canvas .not-support').hide();
$('#win_canvas .select-file').show();
}
}


function next(){
if(fileindex<tableData.length-1) {fileindex=fileindex+1;}
loadimg();
//drawimage();
breadFiles()
showfilelist();
}

function clickLast(){
if(fileindex == 0){
lastindex=true;
prePage();
lastindex=false;

}else{
last();
}
}

function last(){

if(fileindex>0) {fileindex=fileindex-1;}
loadimg();
//drawimage();
breadFiles();
showfilelist();
}


// function showfilelist(){
// var htmlstr="";
// for (var i=0;i<labeltastresult.length;i++){
// var fname = labeltastresult[i].pic_image_field.substring(labeltastresult[i].pic_image_field.lastIndexOf('/') + 1);
// var lablebg=" style=\"cursor:pointer\"";
// if (i==fileindex){lablebg=" style=\"background:#eee;color:#5a5a5a;cursor:pointer;\"";}
// htmlstr = htmlstr+"<tr onclick=\"clickfilelist("+i+");\""+ lablebg+"><td>"+ fname+ "</td></tr>";
// };
// document.getElementById("filelist").innerHTML=htmlstr;
// }

DatasetPreview.prototype.renderText = function (content) {
$('#imgcontent').hide();
$('#win_canvas .select-file').hide();
$('#win_canvas .not-support').hide();
$('#textcontent').empty().text(content).show();
};

function showfilelist(){
// var filename_title = $('a.section:first').text()
// filename_title = filename_title.substring(0,filename_title.lastIndexOf('.'))
var filename_index = labeltastresult[0].pic_image_field.indexOf("/",70);
filename_title = labeltastresult[0].pic_image_field.substring(filename_index + 1);
filename_title = filename_title.substring(0,filename_title.indexOf('/'))
var htmlstr = '';
// htmlstr += '<div class="ui list">';
htmlstr += '<div class="item" style="padding:1.2em;border-bottom:0;display: table;width: 100%;">'
htmlstr += '<i class="caret down icon"></i>'
htmlstr += '<div class="content" style="background:#fff">'
htmlstr += '<div class="header" style="color: rgba(0,0,0,.8);font-size: 12px;font-weight: 600;">'+filename_title+'</div>'
htmlstr += '<div class="list" style="padding:1.2em">'
for (var i=0;i<labeltastresult.length;i++){
var fname = labeltastresult[i].pic_image_field.substring(labeltastresult[i].pic_image_field.lastIndexOf('/') + 1);
//console.log(labeltastresult[i])
if(labeltastresult[i].pic_image_field.length > 70){
var tmpIndex = labeltastresult[i].pic_image_field.indexOf("/",70);
//console.log(tmpIndex)
if(tmpIndex != -1){
fname = labeltastresult[i].pic_image_field.substring(tmpIndex + 1);
fname = fname.substring(fname.indexOf('/')+1);
DatasetPreview.prototype.getFileText = function (file) {
var cache = this.data.fileContentMap[file.ParenDir + file.FileName];
var self = this;
if (false && cache) {
self.renderText(cache);
} else {
$.ajax({
type: "get",
url: "/api/v1/attachments/get_txt_content",
headers: { authorization: this.datasetData.csrf, },
dataType: "json",
data: {
_csrf: this.datasetData.csrf,
uuid: this.datasetData.uuid,
type: this.datasetData.type,
filePath: file.ParenDir + file.FileName,
},
success: function (res) {
self.data.fileContentMap[file.ParenDir + file.FileName] = res.data;
const data = res.data || [];
if (res.result_code == 0) {
self.renderText(data.join(''));
} else if (res.result_code == -1) {
self.renderText(res.msg);
} else {
self.renderNotSupport();
}
},
error: function (err) {
console.log(err);
self.renderNotSupport();
}
});
}
htmlstr += '<div class="item" onclick=\"clickfilelist('+i+');\" style="border-bottom:0;padding-bottom:0.9em;cursor:pointer">'
htmlstr += '<div class="content" style="background:#fff;padding:0;">'
if(i==fileindex){
htmlstr += '<div class="header" style="color: rgba(0,0,0,.8);font-size: 12px;font-weight: 100;color:#0366d6;overflow: hidden;text-overflow:ellipsis;">'+fname+'</div>'
}
else{
htmlstr += '<div class="header" style="color: rgba(0,0,0,.8);font-size: 12px;font-weight: 100;overflow: hidden;text-overflow:ellipsis;">'+fname+'</div>'
}
htmlstr += '</div>'
htmlstr += '</div>'
};
htmlstr += '</div>'
htmlstr += '</div>'
htmlstr += '</div>'
document.getElementById("filelist").innerHTML=htmlstr;
}


function breadFiles(){

// for (var i=0;i<labeltastresult.length;i++){
// var fname_full_path=""
// if(labeltastresult[i].pic_image_field.length > 70){
// var tmp_index = labeltastresult[i].pic_image_field.indexOf("/",70);
// if(tmp_index != -1){
// fname_full_path = labeltastresult[i].pic_image_field.substring(tmp_index + 1);
// }
// var fname_path = fname_full_path.split('/')
// html_breadFile += '<div class="section">'+fname_full_path+'.zip'+'</div>'
// for(var i=1;i<fname_path.length;i++){
// html_breadFile += '<div class="divider" style="opacity:0.8"> / </div>'
// html_breadFile += '<div class="section">'+fname_path[i]+'</div>'

// }
// }
// else{


// }
// }
var fname_full_path=""
var filename_title = $('a.section:first').text()
filename_title = filename_title.substring(0,filename_title.lastIndexOf('.'))
var tmp_index = tableData[fileindex].pic_image_field.indexOf("/",70);
if(tmp_index != -1){
fname_full_path = tableData[fileindex].pic_image_field.substring(tmp_index + 1);
DatasetPreview.prototype.offsetPrview = function (offset) {
var fileList = this.currentFileList.filter(function (item) { return !item.IsDir });
if (!fileList.length) {
this.renderPleseSelectFile();
return;
}
var fname_path = fname_full_path.split('/')
//console.log(fname_path)
// var filename_text = tableData[fileindex].pic_image_field.substring(tableData[fileindex].pic_image_field.lastIndexOf('/')+1)
var html_breadFile = ''
// var source_name = filename_title+'.zip'
// html_breadFile += '<div class="section">'+source_name+'</div>'
// html_breadFile += '<div class="divider" style="opacity:0.8"> / </div>'
html_breadFile += '<div class="section">'+filename_title+'</div>'
html_breadFile += '<div class="divider" style="opacity:0.8"> / </div>'
for (var i=0;i<fname_path.length;i++){
html_breadFile += '<div class="section">'+fname_path[i]+'</div>'
html_breadFile += '<div class="divider" style="opacity:0.8"> / </div>'
var file = this.currentFile;
var index = -1;
var nextIndex = 0;
if (file) {
index = fileList.findIndex(function (item) { return (item.ParenDir + item.FileName) == (file.ParenDir + file.FileName); });
index = Math.max(0, index);
nextIndex = (offset + index + fileList.length) % fileList.length;
}
document.getElementById("breadFile").innerHTML=html_breadFile

}

function showlabelflist(){
if(!isEmpty(labelInfo)){
var resLabelInfo = JSON.parse(labelInfo)
var textInfo = resLabelInfo["type"]
var html_labelFile = ''
for (var i=0;i<textInfo.length;i++){

html_labelFile += `<span style="display:block;width:70%;margin:0.6em 15%;padding-left:1.5em;padding-top:0.4em;padding-bottom:0.4em;font-size:12px;" class="labelInfo">${textInfo[i]}</span>`

}
document.getElementById("labellist").innerHTML=html_labelFile
setColor()
}
else{
return
}

}
function setColor(){
colorinfo1 = ['rgba(0, 199, 255, 0.4)','rgba(114, 46, 209, 0.4)','rgba(188, 100, 164, 0.4)','rgba(153, 204, 0, 0.4)','rgba(51, 204, 153, 0.4)','rgba(255, 204, 51, 0.4)',
'rgba(71, 255, 71, 0.4)','rgba(255, 154, 71, 0.4)','rgba(71, 126, 255, 0.4)','rgba(71, 255, 255, 0.4)','rgba(255, 247, 71, 0.4)','rgba(196, 127, 255, 0.4)','rgba(233, 84, 100, 0.4)',
'rgba(255, 71, 204, 0.4)',' rgba(43, 199, 160, 0.4)']
colorinfo2 = ['#00C7FF','#722ED1','#BC64A4','#99CC00','#33CC99','#FFCC33','#47FF47','#FF9A47','#477EFF','#47FFFF','#FFF747','#C47FFF','#E95464','#FF47CC','#2BC7A0']
var el_span = document.querySelectorAll("span.labelInfo")
for (var i=0;i<el_span.length;i++){
// var colorinfo = ~~(Math.random()*(1<<24))
// var colorinfo1 = '#'+(colorinfo).toString(16)
// var colorinfo2 = '#'+(colorinfo+100).toString(16)
el_span[i].style.backgroundColor = colorinfo1[i]
el_span[i].style.borderLeft = '5px solid'+ colorinfo2[i]
}
this.currentFile = fileList[nextIndex];
var self = this;
$('#filelist .file-item').removeClass('active');
$('#filelist .file-item').map((_, item) => {
var eleObj = $(item);
var data = eleObj.data('data');
if ((data.ParenDir + data.FileName) == (self.currentFile.ParenDir + self.currentFile.FileName)) {
eleObj.addClass('active');
self.renderPreview(data);
}
})
};

}
function getLabelInfo(uuid){
$.ajax({
type:"GET",
url:ip + "/getlabelinfo",
headers: {
authorization:token,
},
dataType:"text",
data:{
'uuid':uuid
},
async:false,
success:function(json){
labelInfo = json;
},
error:function(response) {
DatasetPreview.prototype.eventInit = function () {
var self = this;
$('#filelist').on('click', '.file-item', function () {
var eleObj = $(this);
var file = eleObj.data('data');
if (file.IsDir) {
self.nextDirs(file);
} else {
$('#filelist .file-item').removeClass('active');
eleObj.addClass('active');
self.currentFile = file;
self.renderPreview(file);
}
});
}).on('click', '.file-more', function () {
self.getPathChildrenMore();
});
$('#file_path_container').on('click', '.section', function () {
var eleObj = $(this).parent();
var pathData = eleObj.data('data');
var index = self.data.filePath.findIndex(function (item) { return item.path == pathData.path });
var newPath = self.data.filePath.slice(0, index + 1);
self.data.filePath = newPath;
self.getPathChildren();
});
$('#myCanvas_div').on('click', '.prev_view_btn', function () {
self.offsetPrview(-1);
}).on('click', '.next_view_btn', function () {
self.offsetPrview(1);
});
};

}
$(document).ready(function () {
window.DatasetPreviewController = new DatasetPreview();
})
})();

+ 46
- 3
routers/ai_task/ai_task.go View File

@@ -2,6 +2,10 @@ package ai_task

import (
"archive/zip"
"net/http"
"net/url"
"strings"

"code.gitea.io/gitea/entity"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/cloudbrain"
@@ -13,9 +17,7 @@ import (
"code.gitea.io/gitea/routers/response"
"code.gitea.io/gitea/services/ai_task_service/schedule"
"code.gitea.io/gitea/services/ai_task_service/task"
"net/http"
"net/url"
"strings"
"code.gitea.io/gitea/services/cloudbrain/resource"
)

func CreateAITask(ctx *context.Context, form entity.CreateReq) {
@@ -385,6 +387,47 @@ func GetNodeInfo(ctx *context.Context) {
ctx.JSON(http.StatusOK, response.OuterSuccessWithData(m))
}

func GetImageInfoBySelectedSpec(ctx *context.Context) {
jobType := ctx.Query("job_type")

if models.JobType(jobType) == (models.JobTypeOnlineInference) {
jobType = string(models.JobTypeDebug)
}
log.Info("required jobType=" + jobType)
computeSourceName := ctx.Query("compute_source")
clusterType := ctx.Query("cluster_type")

computeSource := models.GetComputeSourceInstance(computeSourceName)
specId := ctx.QueryInt64("spec_id")
hasInternet := ctx.QueryInt("has_internet")

spec, err := resource.GetAndCheckSpec(ctx.User.ID, specId, models.FindSpecsOptions{
JobType: models.JobType(jobType),
ComputeResource: computeSourceName,
Cluster: clusterType,
HasInternet: models.SpecInternetQuery(hasInternet),
})

if err != nil || spec == nil {
ctx.JSON(http.StatusOK, response.OuterTrBizError(response.SPEC_NOT_AVAILABLE, ctx))
return
}

result, bizerr := task.GetAvailableImageInfoBySpec(entity.GetAITaskCreationImageInfoReq{
ClusterType: entity.ClusterType(clusterType),
ComputeSource: computeSource,
Spec: spec,
JobType: models.JobType(jobType),
UserID: ctx.User.ID,
})
if bizerr != nil {
log.Error("GetAITaskImageCreationInfo error,err=%v", bizerr)
ctx.JSON(http.StatusOK, response.OuterTrBizError(bizerr, ctx))
return
}
ctx.JSON(http.StatusOK, response.OuterSuccessWithData(result))
}

func GetCreationRequiredInfo(ctx *context.Context) {
jobType := ctx.Query("job_type")
var isOnlineType bool


+ 9
- 3
routers/api/v1/api.go View File

@@ -59,10 +59,11 @@
package v1

import (
"code.gitea.io/gitea/routers/reward/point"
"net/http"
"strings"

"code.gitea.io/gitea/routers/reward/point"

"code.gitea.io/gitea/services/memory"

"code.gitea.io/gitea/routers/response"
@@ -657,6 +658,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Post("/restart", reqWeChatStandard(), reqRepoWriter(models.UnitTypeCloudBrain), reqAITaskInRepo(), reqAdminOrAITaskCreator(), ai_task.RestartAITask)
m.Get("/debug_url", reqWeChatStandard(), reqRepoWriter(models.UnitTypeCloudBrain), reqAITaskInRepo(), ai_task.GetNotebookUrl)
m.Get("/creation/required", reqWeChatStandard(), reqRepoWriter(models.UnitTypeCloudBrain), ai_task.GetCreationRequiredInfo)
m.Get("/creation/image_by_spec", reqWeChatStandard(), reqRepoWriter(models.UnitTypeCloudBrain), ai_task.GetImageInfoBySelectedSpec)
m.Post("/output/reschedule", reqRepoWriter(models.UnitTypeCloudBrain), ai_task.RetryModelSchedule)

}, reqToken(), context.RepoRef())
@@ -758,14 +760,17 @@ func RegisterRoutes(m *macaron.Macaron) {
}, reqToken())

m.Group("/attachments", func() {

m.Get("/:uuid", repo.GetAttachment)
m.Get("/get_chunks", repo.GetSuccessChunks)
m.Get("/new_multipart", repo.NewMultipart)
m.Get("/get_multipart_url", repo.GetMultipartUploadUrl)
m.Post("/complete_multipart", repo.CompleteMultipart)

}, reqToken())
m.Group("/attachments", func() {
m.Get("/get_dir", repo.GetAttachmentDir)
m.Get("/get_image_content", repo.GetAttachmentImageContent)
m.Get("/get_txt_content", repo.GetAttachmentTxtContent)
})
m.Group("/attachments/model", func() {
m.Get("/get_chunks", repo.GetModelChunks)
m.Get("/new_multipart", repo.NewModelMultipart)
@@ -852,6 +857,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Get("/cloudbrainboard/cloudbrain/resource_queues", repo.GetResourceQueues)
m.Get("/cloudbrainboard/ai_center_overview", repo.GetCloubrainOverviewGroupByAiCenter)
m.Get("/cloudbrainboard/location", cloudbrainService.GetCloudbrainLocationInfo)
m.Get("/cloudbrainboard/card_data", repo.GetCartStatisticData)

m.Group("/cloudbrainboard", func() {
m.Get("/downloadAll", repo.DownloadCloudBrainBoard)


+ 12
- 0
routers/api/v1/repo/attachments.go View File

@@ -54,6 +54,18 @@ func checkDatasetPermission(ctx *context.APIContext) string {
return ""
}

func GetAttachmentDir(ctx *context.APIContext) {
routeRepo.GetDirSomeFiles(ctx.Context)
}

func GetAttachmentImageContent(ctx *context.APIContext) {
routeRepo.GetImageContent(ctx.Context)
}

func GetAttachmentTxtContent(ctx *context.APIContext) {
routeRepo.GetTxtContent(ctx.Context)
}

func NewMultipart(ctx *context.APIContext) {
if errStr := checkDatasetPermission(ctx); errStr != "" {
ctx.JSON(200, map[string]string{


+ 24
- 21
routers/api/v1/repo/cloudbrain.go View File

@@ -492,13 +492,14 @@ func GetCloudbrainTask(ctx *context.APIContext) {
if job.IsNewAITask() {
jobAfter, _ := task.UpdateCloudbrain(job)
ctx.JSON(http.StatusOK, map[string]interface{}{
"ID": ID,
"JobName": jobAfter.JobName,
"JobStatus": jobAfter.Status,
"SubState": "",
"CreatedTime": jobAfter.CreatedUnix.Format("2006-01-02 15:04:05"),
"CompletedTime": jobAfter.UpdatedUnix.Format("2006-01-02 15:04:05"),
"JobDuration": jobAfter.TrainJobDuration,
"ID": ID,
"JobName": jobAfter.JobName,
"JobStatus": jobAfter.Status,
"DetailedStatus": jobAfter.DetailedStatus,
"SubState": "",
"CreatedTime": jobAfter.CreatedUnix.Format("2006-01-02 15:04:05"),
"CompletedTime": jobAfter.UpdatedUnix.Format("2006-01-02 15:04:05"),
"JobDuration": jobAfter.TrainJobDuration,
})
return
}
@@ -507,13 +508,14 @@ func GetCloudbrainTask(ctx *context.APIContext) {
routerRepo.GetAiSafetyTaskByJob(job)
job, err = models.GetCloudbrainByID(ID)
ctx.JSON(http.StatusOK, map[string]interface{}{
"ID": ID,
"JobName": job.JobName,
"JobStatus": job.Status,
"SubState": "",
"CreatedTime": job.CreatedUnix.Format("2006-01-02 15:04:05"),
"CompletedTime": job.UpdatedUnix.Format("2006-01-02 15:04:05"),
"JobDuration": job.TrainJobDuration,
"ID": ID,
"JobName": job.JobName,
"JobStatus": job.Status,
"DetailedStatus": job.DetailedStatus,
"SubState": "",
"CreatedTime": job.CreatedUnix.Format("2006-01-02 15:04:05"),
"CompletedTime": job.UpdatedUnix.Format("2006-01-02 15:04:05"),
"JobDuration": job.TrainJobDuration,
})
} else {
jobAfter, err := cloudbrainTask.SyncCloudBrainOneStatus(job)
@@ -525,13 +527,14 @@ func GetCloudbrainTask(ctx *context.APIContext) {
}

ctx.JSON(http.StatusOK, map[string]interface{}{
"ID": ID,
"JobName": jobAfter.JobName,
"JobStatus": jobAfter.Status,
"SubState": "",
"CreatedTime": jobAfter.CreatedUnix.Format("2006-01-02 15:04:05"),
"CompletedTime": jobAfter.UpdatedUnix.Format("2006-01-02 15:04:05"),
"JobDuration": jobAfter.TrainJobDuration,
"ID": ID,
"JobName": jobAfter.JobName,
"JobStatus": jobAfter.Status,
"DetailedStatus": jobAfter.DetailedStatus,
"SubState": "",
"CreatedTime": jobAfter.CreatedUnix.Format("2006-01-02 15:04:05"),
"CompletedTime": jobAfter.UpdatedUnix.Format("2006-01-02 15:04:05"),
"JobDuration": jobAfter.TrainJobDuration,
})
}
}


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

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

"code.gitea.io/gitea/routers/response"

"code.gitea.io/gitea/modules/util"

"code.gitea.io/gitea/modules/setting"
@@ -937,6 +939,7 @@ func GetCloudbrainsDetailData(ctx *context.Context) {
taskDetail.JobName = ciTasks[i].JobName
taskDetail.DisplayJobName = ciTasks[i].DisplayJobName
taskDetail.Status = ciTasks[i].Status
taskDetail.DetailedStatus = ciTasks[i].DetailedStatus
taskDetail.JobType = ciTasks[i].JobType
taskDetail.CreatedUnix = ciTasks[i].Cloudbrain.CreatedUnix
taskDetail.RunTime = ciTasks[i].Cloudbrain.TrainJobDuration
@@ -959,7 +962,7 @@ func GetCloudbrainsDetailData(ctx *context.Context) {
taskDetail.CardDuration = repo.GetCloudbrainCardDuration(ciTasks[i].Cloudbrain)
taskDetail.WaitTime = repo.GetCloudbrainWaitTime(ciTasks[i].Cloudbrain)

if ciTasks[i].Cloudbrain.DeletedAt != nilTime || ciTasks[i].Repo == nil {
if ciTasks[i].Cloudbrain.DeletedAt != nilTime {
taskDetail.IsDelete = true
} else {
taskDetail.IsDelete = false
@@ -980,6 +983,28 @@ func GetCloudbrainsDetailData(ctx *context.Context) {
})
}

func GetCartStatisticData(ctx *context.Context) {

dataType := ctx.QueryTrim("type")
category := ctx.QueryTrim("category")

if _, ok := models.XpuInfoType[dataType]; !ok {
ctx.Error(http.StatusBadRequest)
return
}
if _, ok := models.XpuInfoCategories[category]; !ok {
ctx.Error(http.StatusBadRequest)
return
}

result, err := models.GetXPUStatisticInfos(models.XpuInfoType[dataType], category)
if err != nil {
log.Error("can not get statistic info", err)
ctx.JSON(http.StatusOK, response.OuterSuccessWithData([]*models.XPUInfoStatisticShow{}))
}
ctx.JSON(http.StatusOK, response.OuterSuccessWithData(result))
}

func GetCloudbrainsCreateHoursData(ctx *context.Context) {
recordCloudbrain, err := models.GetRecordBeginTime()
if err != nil {


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

@@ -66,11 +66,12 @@ func GetModelArtsNotebook2(ctx *context.APIContext) {

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

}
@@ -143,11 +144,12 @@ func GetModelArtsTrainJobVersion(ctx *context.APIContext) {
}
aiCenterName = cloudbrainService.GetAiCenterShow(job.AiCenter, ctx.Context)
ctx.JSON(http.StatusOK, map[string]interface{}{
"JobID": jobID,
"JobStatus": job.Status,
"JobDuration": job.TrainJobDuration,
"AiCenter": aiCenterName,
"StartTime": job.StartTime,
"JobID": jobID,
"JobStatus": job.Status,
"DetailedStatus": job.DetailedStatus,
"JobDuration": job.TrainJobDuration,
"AiCenter": aiCenterName,
"StartTime": job.StartTime,
})
return
}
@@ -208,11 +210,12 @@ func GetModelArtsTrainJobVersion(ctx *context.APIContext) {
}

ctx.JSON(http.StatusOK, map[string]interface{}{
"JobID": jobID,
"JobStatus": job.Status,
"JobDuration": job.TrainJobDuration,
"AiCenter": aiCenterName,
"StartTime": job.StartTime,
"JobID": jobID,
"JobStatus": job.Status,
"JobDuration": job.TrainJobDuration,
"AiCenter": aiCenterName,
"StartTime": job.StartTime,
"DetailedStatus": job.DetailedStatus,
})

}


+ 6
- 1
routers/home.go View File

@@ -56,7 +56,8 @@ const (
tplRepoSearch base.TplName = "explore/repos/search"
tplRoshmci base.TplName = "explore/ros-hmci"

tplExploreCenterMap base.TplName = "explore/center_map"
tplExploreCenterMap base.TplName = "explore/center_map"
tplExploreDomestic base.TplName = "explore/domestic"
)

// Home render home page
@@ -820,6 +821,10 @@ func ExploreImages(ctx *context.Context) {
ctx.HTML(200, tplExploreImages)
}

func ExploreDomestic(ctx *context.Context) {
ctx.HTML(200, tplExploreDomestic)
}

func ExploreDataAnalysisUserTrend(ctx *context.Context) {
ctx.Data["url_params"] = "UserTrend"
ctx.HTML(200, tplExploreExploreDataAnalysis)


+ 33
- 13
routers/org/teams.go View File

@@ -6,6 +6,7 @@
package org

import (
"fmt"
"net/http"
"path"
"strings"
@@ -310,18 +311,37 @@ func EditTeamPost(ctx *context.Context, form auth.CreateTeamForm) {
}
t.Description = form.Description
if t.Authorize < models.AccessModeOwner {
var units = make([]models.TeamUnit, 0, len(form.Units))
for _, tp := range form.Units {
units = append(units, models.TeamUnit{
OrgID: t.OrgID,
TeamID: t.ID,
Type: tp,
})
}
err := models.UpdateTeamUnits(t, units)
if err != nil {
ctx.Error(http.StatusInternalServerError, "LoadIssue", err.Error())
return
log.Info("t.Authorize < models.AccessModeOwner")
if t.Authorize < models.AccessModeAdmin {
var units = make([]models.TeamUnit, 0, len(form.Units))
for _, tp := range form.Units {
units = append(units, models.TeamUnit{
OrgID: t.OrgID,
TeamID: t.ID,
Type: tp,
})
}
err := models.UpdateTeamUnits(t, units)
if err != nil {
ctx.Error(http.StatusInternalServerError, "LoadIssue", err.Error())
return
}
} else {
log.Info("t.Authorize = models.AccessModeAdmin")

var units = make([]models.TeamUnit, 0, len(models.AllRepoUnitTypes))
for _, tp := range models.AllRepoUnitTypes {
units = append(units, models.TeamUnit{
OrgID: t.OrgID,
TeamID: t.ID,
Type: tp,
})
}
err := models.UpdateTeamUnits(t, units)
if err != nil {
ctx.Error(http.StatusInternalServerError, "LoadIssue", err.Error())
return
}
}
}
t.CanCreateOrgRepo = form.CanCreateOrgRepo
@@ -335,7 +355,7 @@ func EditTeamPost(ctx *context.Context, form auth.CreateTeamForm) {
ctx.RenderWithErr(ctx.Tr("form.team_no_units_error"), tplTeamNew, &form)
return
}
log.Info("isAuthChanged=" + fmt.Sprint(isAuthChanged) + " isIncludeAllChanged=" + fmt.Sprint(isIncludeAllChanged))
if err := models.UpdateTeam(t, isAuthChanged, isIncludeAllChanged); err != nil {
ctx.Data["Err_TeamName"] = true
switch {


+ 368
- 0
routers/repo/attachment_dir.go View File

@@ -0,0 +1,368 @@
package repo

import (
"bufio"
"encoding/json"
"errors"
"fmt"
"io"
"path"
"strings"
"time"

"golang.org/x/text/encoding/simplifiedchinese"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/redis/redis_client"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/storage"
)

type DirRedisCache struct {
DirList []storage.FileInfo
Marker string
}

func GetDirSomeFiles(ctx *context.Context) {
uuid := ctx.Query("uuid")
marker := ctx.Query("marker")
pageSize := ctx.QueryInt("pageSize")
prefix := ctx.Query("prefix")
cacheKey := uuid + prefix + marker + " " + fmt.Sprint(pageSize)
//delimiter := ctx.Query("delimiter")
attach, err := models.GetAttachmentByUUID(uuid)
if err == nil {
cacheResult, err := getAttachmentDirFromCache(cacheKey)
if err == nil {
log.Info("load from cache.")
ctx.JSON(200, map[string]interface{}{
"result_code": "0",
"data": cacheResult.DirList,
"marker": cacheResult.Marker,
})
return
}
if attach.Type == models.TypeCloudBrainOne {
re, marker, err := storage.GetDirsSomeFileMinio(setting.Attachment.Minio.Bucket,
setting.Attachment.Minio.BasePath+
models.AttachmentRelativePath(attach.UUID)+
attach.UUID, prefix, marker, pageSize)
if err == nil {
setAttachmentDirToCache(cacheKey, DirRedisCache{
DirList: re,
Marker: marker,
})
ctx.JSON(200, map[string]interface{}{
"result_code": "0",
"data": re,
"marker": marker,
})
return
}
} else if attach.Type == models.TypeCloudBrainTwo {
re, marker, err := storage.GetDirsSomeFile(setting.Bucket,
setting.BasePath+
models.AttachmentRelativePath(attach.UUID)+
attach.UUID, prefix, marker, pageSize)
if err == nil {
setAttachmentDirToCache(cacheKey, DirRedisCache{
DirList: re,
Marker: marker,
})
ctx.JSON(200, map[string]interface{}{
"result_code": "0",
"data": re,
"marker": marker,
})
return
}
}
}
ctx.JSON(200, map[string]interface{}{
"result_code": "-1",
"data": "",
})
}

func GetImageContent(ctx *context.Context) {
uuid := ctx.Query("uuid")
fileName := ctx.Query("filePath")
storageType := ctx.QueryInt("type")
if storageType == 0 {
getMinioImageContent(uuid, fileName, ctx)
} else {
if storageType == 1 {
getObsImageContent(uuid, fileName, ctx)
}
}
}

func GetTxtContent(ctx *context.Context) {
uuid := ctx.Query("uuid")
fileName := ctx.Query("filePath")
storageType := ctx.QueryInt("type")
if storageType == 0 {
getMinioTxtContent(uuid, fileName, ctx)
} else {
if storageType == 1 {
getObsTxtContent(uuid, fileName, ctx)
}
}
}

func getObsImageContent(uuid string, fileName string, ctx *context.Context) {
objectName := strings.TrimPrefix(path.Join(setting.BasePath+models.AttachmentRelativePath(uuid)+uuid, fileName), "/")
//log.Info("obs objectName=" + objectName)
body, err := storage.ObsDownloadAFile(setting.Bucket, objectName)
if err != nil {
log.Info("upload error.")
} else {
defer body.Close()
ctx.Resp.Header().Set("Content-Type", "image/jpg;charset=utf-8")
p := make([]byte, 1024)
var readErr error
var readCount int
// 读取对象内容
for {
readCount, readErr = body.Read(p)
if readCount > 0 {
ctx.Resp.Write(p[:readCount])
}
if readErr != nil {
break
}
}
}
}

func getObsTxtContent(uuid string, fileName string, ctx *context.Context) {
objectName := strings.TrimPrefix(path.Join(setting.BasePath+models.AttachmentRelativePath(uuid)+uuid, fileName), "/")
//log.Info("obs objectName=" + objectName)
body, err := storage.ObsDownloadAFile(setting.Bucket, objectName)
if err != nil {
log.Info("download error.")
ctx.JSON(200, map[string]interface{}{
"result_code": "-1",
"msg": "Read file error.",
"data": "",
})
return
} else {
readS3Body(body, ctx)
}
}

func readS3Body(body io.ReadCloser, ctx *context.Context) {
defer body.Close()
result := make([]string, 0)
r := bufio.NewReader(body)
size := 0
for {
line, err := r.ReadString('\n')
if err == io.EOF {
result = append(result, toUTF8(line))
size += len(line)
if !toDealLine(result, line, size, ctx) {
return
}
break
}
if err != nil {
log.Info("read error,err=" + err.Error())
break
}
result = append(result, toUTF8(line))
size += len(line)
if !toDealLine(result, line, size, ctx) {
return
}
}
ctx.JSON(200, map[string]interface{}{
"result_code": "0",
"msg": "",
"data": result,
})
}

func toDealLine(result []string, line string, size int, ctx *context.Context) bool {
log.Info("line count=" + fmt.Sprint(len(result)) + " size=" + fmt.Sprint(size))
if len(result) > 2000 || size > 2*1024*1024 {
ctx.JSON(200, map[string]interface{}{
"result_code": "-1",
"msg": ctx.Tr("repo.attachmentfilesizetobig"),
"data": "",
})
return false
}
return true
}

func toUTF8(line string) string {
lineBytes := []byte(line)
if isUtf8(lineBytes) {
return line
}
if isGBK(lineBytes) {
log.Info("this is gbk")
gbkBytes, err := simplifiedchinese.GBK.NewDecoder().Bytes(lineBytes) //gbk 转 utf-8
if err == nil {
return string(gbkBytes)
}
}
return line
}

func toGBK(line string) string {
lineBytes := []byte(line)
if !isGBK(lineBytes) {
gbkBytes, err := simplifiedchinese.GBK.NewEncoder().Bytes(lineBytes) //utf-8 转 gbk
if err == nil {
return string(gbkBytes)
}
}
return line
}

func isGBK(data []byte) bool {
length := len(data)
var i int = 0
for i < length {
//fmt.Printf("for %x\n", data[i])
if data[i] <= 0xff {
//编码小于等于127,只有一个字节的编码,兼容ASCII吗
i++
continue
} else {
//大于127的使用双字节编码
if data[i] >= 0x81 &&
data[i] <= 0xfe &&
data[i+1] >= 0x40 &&
data[i+1] <= 0xfe &&
data[i+1] != 0xf7 {
i += 2
continue
} else {
return false
}
}
}
return true
}

func getMinioImageContent(uuid string, fileName string, ctx *context.Context) {
objectName := strings.TrimPrefix(path.Join(setting.Attachment.Minio.BasePath+models.AttachmentRelativePath(uuid)+uuid, fileName), "/")
//log.Info("minio objectName=" + objectName)
body, err := storage.Attachments.DownloadAFile(setting.Attachment.Minio.Bucket, objectName)
if err != nil {
log.Info("download error.")
} else {
defer body.Close()
ctx.Resp.Header().Set("Content-Type", "image/jpg;charset=utf-8")
p := make([]byte, 1024)
var readErr error
var readCount int
// 读取对象内容
for {
readCount, readErr = body.Read(p)
if readCount > 0 {
ctx.Resp.Write(p[:readCount])
}
if readErr != nil {
break
}
}
}
}

func getMinioTxtContent(uuid string, fileName string, ctx *context.Context) {
objectName := strings.TrimPrefix(path.Join(setting.Attachment.Minio.BasePath+models.AttachmentRelativePath(uuid)+uuid, fileName), "/")
//log.Info("minio objectName=" + objectName)
body, err := storage.Attachments.DownloadAFile(setting.Attachment.Minio.Bucket, objectName)
if err != nil {
log.Info("download error.")
ctx.JSON(200, map[string]interface{}{
"result_code": "-1",
"msg": "Read file error.",
"data": "",
})
return
} else {
readS3Body(body, ctx)
}
}

func preNUm(data byte) int {
str := fmt.Sprintf("%b", data)
var i int = 0
for i < len(str) {
if str[i] != '1' {
break
}
i++
}
return i
}

func isUtf8(data []byte) bool {
for i := 0; i < len(data); {
if data[i]&0x80 == 0x00 {
// 0XXX_XXXX
i++
continue
} else if num := preNUm(data[i]); num > 2 {
// 110X_XXXX 10XX_XXXX
// 1110_XXXX 10XX_XXXX 10XX_XXXX
// 1111_0XXX 10XX_XXXX 10XX_XXXX 10XX_XXXX
// 1111_10XX 10XX_XXXX 10XX_XXXX 10XX_XXXX 10XX_XXXX
// 1111_110X 10XX_XXXX 10XX_XXXX 10XX_XXXX 10XX_XXXX 10XX_XXXX
// preNUm() 返回首个字节的8个bits中首个0bit前面1bit的个数,该数量也是该字符所使用的字节数
i++
for j := 0; j < num-1; j++ {
//判断后面的 num - 1 个字节是不是都是10开头
if data[i]&0xc0 != 0x80 {
return false
}
i++
}
} else {
//其他情况说明不是utf-8
return false
}
}
return true
}

func setAttachmentDirToCache(msgKey string, dirList DirRedisCache) {
msgMapJson, _ := json.Marshal(dirList)
redisValue := string(msgMapJson)
log.Info("set redis key=" + msgKey + " value=" + redisValue)
re, err := redis_client.Setex(msgKey, redisValue, 7*24*3600*time.Second)
if err == nil {
log.Info("re =" + fmt.Sprint(re))
} else {
log.Info("set redis error:" + err.Error())
}
}

func getAttachmentDirFromCache(msgKey string) (*DirRedisCache, error) {
valueStr, err := redis_client.Get(msgKey)
//msgMap := make(map[string]string, 0)
fileInfos := &DirRedisCache{}
if err == nil {
if valueStr != "" {
err1 := json.Unmarshal([]byte(valueStr), fileInfos)
if err1 != nil {
log.Info("unmarshal json failed. " + err1.Error())
return nil, err1
}
} else {
return nil, errors.New("cache is empty.")
}
} else {
log.Info("Failed to load from reids. " + err.Error())
return nil, err
}
return fileInfos, nil
}

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

@@ -127,6 +127,7 @@ func DirIndex(ctx *context.Context) {
ctx.Data["Path"] = dirArray
ctx.Data["Dirs"] = true
ctx.Data["Uuid"] = uuid
ctx.Data["Type"] = attachment.Type
ctx.Data["PageIsDataset"] = true

ctx.HTML(200, tplDirIndex)


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

@@ -43,7 +43,7 @@ func ServeData(ctx *context.Context, name string, reader io.Reader) error {
cs = "utf-8"
}
ctx.Resp.Header().Set("Content-Type", "text/plain; charset="+strings.ToLower(cs))
} else if base.IsImageFile(buf) || base.IsPDFFile(buf) {
} else if base.IsImageFile(buf) {
ctx.Resp.Header().Set("Content-Disposition", fmt.Sprintf(`inline; filename="%s"`, name))
} else {
ctx.Resp.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, name))


+ 8
- 7
routers/repo/grampus.go View File

@@ -1356,13 +1356,14 @@ func GetGrampusNotebook(ctx *context.APIContext) {
}

ctx.JSON(http.StatusOK, map[string]interface{}{
"ID": ID,
"JobName": jobAfter.JobName,
"JobStatus": jobAfter.Status,
"AiCenter": aiCenterName,
"CreatedTime": jobAfter.CreatedUnix.Format("2006-01-02 15:04:05"),
"CompletedTime": jobAfter.UpdatedUnix.Format("2006-01-02 15:04:05"),
"JobDuration": jobAfter.TrainJobDuration,
"ID": ID,
"JobName": jobAfter.JobName,
"JobStatus": jobAfter.Status,
"DetailedStatus": jobAfter.DetailedStatus,
"AiCenter": aiCenterName,
"CreatedTime": jobAfter.CreatedUnix.Format("2006-01-02 15:04:05"),
"CompletedTime": jobAfter.UpdatedUnix.Format("2006-01-02 15:04:05"),
"JobDuration": jobAfter.TrainJobDuration,
})
}



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

@@ -37,3 +37,5 @@ var BRANCH_NOT_EXISTS = &BizError{Code: 2020, DefaultMsg: "The branch does not e
var MODEL_NUM_OVER_LIMIT = &BizError{Code: 2021, DefaultMsg: "The number of models exceeds the limit of 30", TrCode: "repo.debug.manage.model_num_over_limit"}
var DATASET_NUMBER_OVER_LIMIT = &BizError{Code: 2022, DefaultMsg: "The dataset count exceed the limit", TrCode: "ai_task.dataset_number_over_limit"}
var NOTEBOOK_EXCEED_MAX_NUM = &BizError{Code: 2023, DefaultMsg: "You can have up to 5 Debug Tasks, please try again after delete some tasks. ", TrCode: "ai_task.too_many_notebook"}
var CAN_NOT_STOP_CREATING_JOB = &BizError{Code: 2024, DefaultMsg: "AI task is creating, can not be stopped", TrCode: "ai_task.can_not_stop_creating_job"}
var NO_CENTER_MATCH = &BizError{Code: 2024, DefaultMsg: "", TrCode: "ai_task.no_center_match"}

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

@@ -431,6 +431,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Get("/data_analysis/Overview", routers.ExploreDataAnalysisOverview)
m.Get("/data_analysis/BrainAnalysis", routers.ExploreDataAnalysisBrainAnalysis)
m.Get("/center_map", reqSignIn, routers.CenterMapUI)
m.Get("/domestic", routers.ExploreDomestic)

}, ignSignIn)
m.Combo("/install", routers.InstallInit).Get(routers.Install).


+ 35
- 12
services/ai_task_service/cluster/c2net.go View File

@@ -59,7 +59,7 @@ func (c C2NetClusterAdapter) CreateOnlineInfer(req entity.CreateNoteBookTaskRequ
return convertGrampus2NoteBookRes(jobResult), nil
}

func (c C2NetClusterAdapter) GetNotebookImages(req entity.GetImageReq) ([]entity.ClusterImage, bool, error) {
func (c C2NetClusterAdapter) GetNotebookImages(req entity.GetImageReq, centerId ...string) ([]entity.ClusterImage, bool, error) {
processType := req.ComputeSource.FullName
images, err := grampus.GetImages(processType, string(req.JobType))
if err != nil {
@@ -69,15 +69,37 @@ func (c C2NetClusterAdapter) GetNotebookImages(req entity.GetImageReq) ([]entity
if images == nil || images.Infos == nil || len(images.Infos) == 0 {
return nil, true, err
}
r := make([]entity.ClusterImage, len(images.Infos))
for i, v := range images.Infos {
r[i] = ConvertGrampusImageToStandard(v)

r := make([]entity.ClusterImage, 0)
for _, v := range images.Infos {
if hasIntersection(v.AICenterImage, centerId...) {
r = append(r, ConvertGrampusImageToStandard(v))
}
}
if len(r) == 0 {
return nil, false, nil
}

return r, false, nil
}

func (c C2NetClusterAdapter) GetTrainImages(req entity.GetImageReq) ([]entity.ClusterImage, bool, error) {
return c.GetNotebookImages(req)
func hasIntersection(imageCenterInfos []models.AICenterImage, centerId ...string) bool {
if len(centerId) == 0 || len(imageCenterInfos) == 0 {
//如果没传centerId或者查询的镜像不含可用中心信息,不进行判断,直接返回true
return true
}
for _, aicenterImage := range imageCenterInfos {
for _, centerCode := range centerId {
if aicenterImage.AICenterID == centerCode {
return true
}
}
}
return false
}

func (c C2NetClusterAdapter) GetTrainImages(req entity.GetImageReq, centerId ...string) ([]entity.ClusterImage, bool, error) {
return c.GetNotebookImages(req, centerId...)
}

func ConvertGrampusImageToStandard(image models.GrampusImage) entity.ClusterImage {
@@ -658,12 +680,13 @@ func convertGrampusTrainJobResponse(job models.GrampusJobInfo) *entity.QueryTask
centerName = task.CenterName[0]
}
return &entity.QueryTaskResponse{
StartedAt: timeutil.TimeStamp(job.StartedAt),
CompletedAt: timeutil.TimeStamp(job.CompletedAt),
Status: job.Status,
CenterId: centerId,
CenterName: centerName,
JobId: job.JobID,
StartedAt: timeutil.TimeStamp(job.StartedAt),
CompletedAt: timeutil.TimeStamp(job.CompletedAt),
Status: job.Status,
DetailedStatus: job.DetailedStatus,
CenterId: centerId,
CenterName: centerName,
JobId: job.JobID,
}
}



+ 2
- 2
services/ai_task_service/cluster/cloudbrain_one.go View File

@@ -37,11 +37,11 @@ func (c CloudbrainOneClusterAdapter) CreateOnlineInfer(req entity.CreateNoteBook
return nil, nil
}

func (c CloudbrainOneClusterAdapter) GetNotebookImages(req entity.GetImageReq) ([]entity.ClusterImage, bool, error) {
func (c CloudbrainOneClusterAdapter) GetNotebookImages(req entity.GetImageReq, centerId ...string) ([]entity.ClusterImage, bool, error) {
return nil, true, nil
}

func (c CloudbrainOneClusterAdapter) GetTrainImages(req entity.GetImageReq) ([]entity.ClusterImage, bool, error) {
func (c CloudbrainOneClusterAdapter) GetTrainImages(req entity.GetImageReq, centerId ...string) ([]entity.ClusterImage, bool, error) {
return c.GetNotebookImages(req)
}



+ 9
- 3
services/ai_task_service/cluster/cloudbrain_two.go View File

@@ -52,13 +52,19 @@ func (c CloudbrainTwoClusterAdapter) CreateNoteBook(req entity.CreateNoteBookTas
WorkspaceID: "0",
})
} else {
var poolId = poolInfos.PoolInfo[0].PoolId
for _, poolInfo := range poolInfos.PoolInfo {
if poolInfo.PoolName == t.Spec.QueueCode {
poolId = poolInfo.PoolId
}
}
jobResult, err = cloudbrain_two.CreateNotebook2(models.CreateNotebook2Params{
JobName: req.Name,
Description: req.Description,
Flavor: t.Spec.SourceSpecId,
Duration: t.AutoStopDuration,
ImageID: t.ImageId,
PoolID: poolInfos.PoolInfo[0].PoolId,
PoolID: poolId,
Feature: models.NotebookFeature,
Volume: models.VolumeReq{
Capacity: setting.Capacity,
@@ -82,7 +88,7 @@ func (c CloudbrainTwoClusterAdapter) CreateOnlineInfer(req entity.CreateNoteBook

var cloudbrainTwoNotebookImages []entity.ClusterImage

func (c CloudbrainTwoClusterAdapter) GetNotebookImages(req entity.GetImageReq) ([]entity.ClusterImage, bool, error) {
func (c CloudbrainTwoClusterAdapter) GetNotebookImages(req entity.GetImageReq, centerId ...string) ([]entity.ClusterImage, bool, error) {
if cloudbrainTwoNotebookImages == nil || len(cloudbrainTwoNotebookImages) == 0 {
images := setting.StImageInfos.ImageInfo
cloudbrainTwoNotebookImages = make([]entity.ClusterImage, len(images))
@@ -99,7 +105,7 @@ func (c CloudbrainTwoClusterAdapter) GetNotebookImages(req entity.GetImageReq) (

var cloudbrainTwoTrainImages []entity.ClusterImage

func (c CloudbrainTwoClusterAdapter) GetTrainImages(req entity.GetImageReq) ([]entity.ClusterImage, bool, error) {
func (c CloudbrainTwoClusterAdapter) GetTrainImages(req entity.GetImageReq, centerId ...string) ([]entity.ClusterImage, bool, error) {
if cloudbrainTwoTrainImages == nil || len(cloudbrainTwoTrainImages) == 0 {
var versionInfos modelarts.VersionInfo
if err := json.Unmarshal([]byte(setting.EngineVersions), &versionInfos); err != nil {


+ 2
- 2
services/ai_task_service/cluster/cluster_base.go View File

@@ -48,7 +48,7 @@ type ClusterAdapter interface {
GetResourceUsage(opts entity.ClusterResourceUsageOpts) (*entity.ResourceUsage, error)
//GetImages return available list of clusters
//The second parameter will return true if image is no limit
GetNotebookImages(req entity.GetImageReq) ([]entity.ClusterImage, bool, error)
GetTrainImages(req entity.GetImageReq) ([]entity.ClusterImage, bool, error)
GetNotebookImages(req entity.GetImageReq, centerId ...string) ([]entity.ClusterImage, bool, error)
GetTrainImages(req entity.GetImageReq, centerId ...string) ([]entity.ClusterImage, bool, error)
CreateOnlineInfer(req entity.CreateNoteBookTaskRequest) (*entity.CreateNoteBookTaskResponse, error)
}

+ 12
- 6
services/ai_task_service/task/cloudbrain_one_notebook_task.go View File

@@ -133,6 +133,16 @@ func (g CloudbrainOneNotebookTaskTemplate) CallCreationAPI(ctx *context.Creation
return response.SYSTEM_ERROR
}
form := ctx.Request

centerIds, bizErr := GetAvailableCenterIds(ctx.Spec, models.GetAvailableCenterIdOpts{
UserId: ctx.User.ID,
JobType: g.JobType,
HasInternet: form.HasInternet,
}, form.ComputeSource, form.ImageID, g.ClusterType)
if bizErr != nil {
return bizErr
}

req := entity.CreateNoteBookTaskRequest{
Name: form.JobName,
Tasks: []entity.NoteBookTask{
@@ -147,12 +157,8 @@ func (g CloudbrainOneNotebookTaskTemplate) CallCreationAPI(ctx *context.Creation
OutPut: ctx.GetContainerDataArray(entity.ContainerOutPutPath),
AutoStopDuration: autoStopDurationMs,
Capacity: setting.Capacity,
CenterID: ctx.Spec.GetAvailableCenterIds(models.GetAvailableCenterIdOpts{
UserId: ctx.User.ID,
JobType: g.JobType,
HasInternet: form.HasInternet,
}),
Spec: ctx.Spec,
CenterID: centerIds,
Spec: ctx.Spec,
},
},
}


+ 29
- 21
services/ai_task_service/task/cloudbrain_one_train_task.go View File

@@ -97,6 +97,14 @@ func (g CloudbrainOneTrainTaskTemplate) CallCreationAPI(ctx *context.CreationCon
return response.SYSTEM_ERROR
}
form := ctx.Request
centerIds, bizErr := GetAvailableCenterIds(ctx.Spec, models.GetAvailableCenterIdOpts{
UserId: ctx.User.ID,
JobType: g.JobType,
HasInternet: form.HasInternet,
}, form.ComputeSource, form.ImageID, g.ClusterType)
if bizErr != nil {
return bizErr
}
req := entity.CreateTrainTaskRequest{
Name: form.JobName,
DisplayJobName: form.DisplayJobName,
@@ -108,17 +116,13 @@ func (g CloudbrainOneTrainTaskTemplate) CallCreationAPI(ctx *context.CreationCon
ImageUrl: strings.TrimSpace(form.ImageUrl),
Datasets: ctx.GetContainerDataArray(entity.ContainerDataset),
Code: ctx.GetContainerDataArray(entity.ContainerCode),
CenterID: ctx.Spec.GetAvailableCenterIds(models.GetAvailableCenterIdOpts{
UserId: ctx.User.ID,
JobType: g.JobType,
HasInternet: form.HasInternet,
}),
PreTrainModel: ctx.GetContainerDataArray(entity.ContainerPreTrainModel),
BootFile: form.BootFile,
OutPut: ctx.GetContainerDataArray(entity.ContainerOutPutPath),
LogPath: ctx.GetContainerDataArray(entity.ContainerLogPath),
Params: form.ParamArray,
Spec: ctx.Spec,
CenterID: centerIds,
PreTrainModel: ctx.GetContainerDataArray(entity.ContainerPreTrainModel),
BootFile: form.BootFile,
OutPut: ctx.GetContainerDataArray(entity.ContainerOutPutPath),
LogPath: ctx.GetContainerDataArray(entity.ContainerLogPath),
Params: form.ParamArray,
Spec: ctx.Spec,
},
},
}
@@ -142,6 +146,14 @@ func (g CloudbrainOneTrainTaskTemplate) CallRestartAPI(ctx *context.CreationCont
return response.SYSTEM_ERROR
}
form := ctx.Request
centerIds, bizErr := GetAvailableCenterIds(ctx.Spec, models.GetAvailableCenterIdOpts{
UserId: ctx.User.ID,
JobType: g.JobType,
HasInternet: form.HasInternet,
}, form.ComputeSource, form.ImageID, g.ClusterType)
if bizErr != nil {
return bizErr
}
req := entity.CreateTrainTaskRequest{
Name: form.JobName,
DisplayJobName: form.DisplayJobName,
@@ -153,16 +165,12 @@ func (g CloudbrainOneTrainTaskTemplate) CallRestartAPI(ctx *context.CreationCont
ImageUrl: strings.TrimSpace(form.ImageUrl),
Datasets: ctx.GetContainerDataArray(entity.ContainerDataset),
Code: ctx.GetContainerDataArray(entity.ContainerCode),
CenterID: ctx.Spec.GetAvailableCenterIds(models.GetAvailableCenterIdOpts{
UserId: ctx.User.ID,
JobType: g.JobType,
HasInternet: form.HasInternet,
}),
PreTrainModel: ctx.GetContainerDataArray(entity.ContainerPreTrainModel),
BootFile: form.BootFile,
OutPut: ctx.GetContainerDataArray(entity.ContainerOutPutPath),
Params: form.ParamArray,
Spec: ctx.Spec,
CenterID: centerIds,
PreTrainModel: ctx.GetContainerDataArray(entity.ContainerPreTrainModel),
BootFile: form.BootFile,
OutPut: ctx.GetContainerDataArray(entity.ContainerOutPutPath),
Params: form.ParamArray,
Spec: ctx.Spec,
},
},
}


+ 16
- 12
services/ai_task_service/task/cloudbrain_two_train_task.go View File

@@ -115,24 +115,28 @@ func (g CloudbrainTwoTrainTaskTemplate) CallCreationAPI(ctx *context.CreationCon
}
}
form := ctx.Request
centerIds, bizErr := GetAvailableCenterIds(ctx.Spec, models.GetAvailableCenterIdOpts{
UserId: ctx.User.ID,
JobType: g.JobType,
HasInternet: form.HasInternet,
}, form.ComputeSource, form.ImageID, g.ClusterType)
if bizErr != nil {
return bizErr
}
req := entity.CreateTrainTaskRequest{
Name: form.JobName,
DisplayJobName: form.DisplayJobName,
Description: form.Description,
Tasks: []entity.TrainTask{
{
Name: form.JobName,
ResourceSpecId: ctx.Spec.SourceSpecId,
ImageId: form.ImageID,
ImageUrl: strings.TrimSpace(form.ImageUrl),
Datasets: ctx.GetContainerDataArray(entity.ContainerDataset),
Code: ctx.GetContainerDataArray(entity.ContainerCode),
LogPath: ctx.GetContainerDataArray(entity.ContainerLogPath),
CenterID: ctx.Spec.GetAvailableCenterIds(models.GetAvailableCenterIdOpts{
UserId: ctx.User.ID,
JobType: g.JobType,
HasInternet: form.HasInternet,
}),
Name: form.JobName,
ResourceSpecId: ctx.Spec.SourceSpecId,
ImageId: form.ImageID,
ImageUrl: strings.TrimSpace(form.ImageUrl),
Datasets: ctx.GetContainerDataArray(entity.ContainerDataset),
Code: ctx.GetContainerDataArray(entity.ContainerCode),
LogPath: ctx.GetContainerDataArray(entity.ContainerLogPath),
CenterID: centerIds,
PreTrainModel: ctx.GetContainerDataArray(entity.ContainerPreTrainModel),
BootFile: form.BootFile,
OutPut: ctx.GetContainerDataArray(entity.ContainerOutPutPath),


+ 10
- 6
services/ai_task_service/task/grampus_notebook_task.go View File

@@ -199,6 +199,14 @@ func (g GrampusNoteBookTaskTemplate) CallCreationAPI(ctx *context.CreationContex
return response.SYSTEM_ERROR
}
form := ctx.Request
centerIds, bizErr := GetAvailableCenterIds(ctx.Spec, models.GetAvailableCenterIdOpts{
UserId: ctx.User.ID,
JobType: g.JobType,
HasInternet: form.HasInternet,
}, form.ComputeSource, form.ImageID, g.ClusterType)
if bizErr != nil {
return bizErr
}
imageUrl := strings.TrimSpace(form.ImageUrl)
if form.ImageID != "" {
imageUrl = ""
@@ -215,12 +223,8 @@ func (g GrampusNoteBookTaskTemplate) CallCreationAPI(ctx *context.CreationContex
Code: ctx.GetContainerDataArray(entity.ContainerCode),
AutoStopDuration: autoStopDurationMs,
Capacity: setting.Capacity,
CenterID: ctx.Spec.GetAvailableCenterIds(models.GetAvailableCenterIdOpts{
UserId: ctx.User.ID,
JobType: g.JobType,
HasInternet: form.HasInternet,
}),
Spec: ctx.Spec,
CenterID: centerIds,
Spec: ctx.Spec,
},
},
}


+ 11
- 7
services/ai_task_service/task/grampus_online_infer_task.go View File

@@ -95,6 +95,14 @@ func (g GrampusOnlineInferTaskTemplate) CallCreationAPI(ctx *context.CreationCon
return response.SYSTEM_ERROR
}
form := ctx.Request
centerIds, bizErr := GetAvailableCenterIds(ctx.Spec, models.GetAvailableCenterIdOpts{
UserId: ctx.User.ID,
JobType: g.JobType,
HasInternet: form.HasInternet,
}, form.ComputeSource, form.ImageID, g.ClusterType)
if bizErr != nil {
return bizErr
}
imageUrl := strings.TrimSpace(form.ImageUrl)
if form.ImageID != "" {
imageUrl = ""
@@ -119,13 +127,9 @@ func (g GrampusOnlineInferTaskTemplate) CallCreationAPI(ctx *context.CreationCon
OutPut: ctx.GetContainerDataArray(entity.ContainerOutPutPath),
AutoStopDuration: -1,
Capacity: setting.Capacity,
CenterID: ctx.Spec.GetAvailableCenterIds(models.GetAvailableCenterIdOpts{
UserId: ctx.User.ID,
JobType: g.JobType,
HasInternet: form.HasInternet,
}),
Spec: ctx.Spec,
BootFile: ctx.Request.BootFile,
CenterID: centerIds,
Spec: ctx.Spec,
BootFile: ctx.Request.BootFile,
},
},
}


+ 29
- 21
services/ai_task_service/task/grampus_train_task.go View File

@@ -131,6 +131,14 @@ func (g GrampusTrainTaskTemplate) CallCreationAPI(ctx *context.CreationContext)
return response.SYSTEM_ERROR
}
form := ctx.Request
centerIds, bizErr := GetAvailableCenterIds(ctx.Spec, models.GetAvailableCenterIdOpts{
UserId: ctx.User.ID,
JobType: g.JobType,
HasInternet: form.HasInternet,
}, form.ComputeSource, form.ImageID, g.ClusterType)
if bizErr != nil {
return bizErr
}
imageUrl := strings.TrimSpace(form.ImageUrl)
if form.ImageID != "" {
imageUrl = ""
@@ -140,17 +148,13 @@ func (g GrampusTrainTaskTemplate) CallCreationAPI(ctx *context.CreationContext)
DisplayJobName: form.DisplayJobName,
Tasks: []entity.TrainTask{
{
Name: form.JobName,
ResourceSpecId: ctx.Spec.SourceSpecId,
ImageId: form.ImageID,
ImageUrl: imageUrl,
Datasets: ctx.GetContainerDataArray(entity.ContainerDataset),
Code: ctx.GetContainerDataArray(entity.ContainerCode),
CenterID: ctx.Spec.GetAvailableCenterIds(models.GetAvailableCenterIdOpts{
UserId: ctx.User.ID,
JobType: g.JobType,
HasInternet: form.HasInternet,
}),
Name: form.JobName,
ResourceSpecId: ctx.Spec.SourceSpecId,
ImageId: form.ImageID,
ImageUrl: imageUrl,
Datasets: ctx.GetContainerDataArray(entity.ContainerDataset),
Code: ctx.GetContainerDataArray(entity.ContainerCode),
CenterID: centerIds,
PreTrainModel: ctx.GetContainerDataArray(entity.ContainerPreTrainModel),
BootFile: form.BootFile,
OutPut: ctx.GetContainerDataArray(entity.ContainerOutPutPath),
@@ -182,6 +186,14 @@ func (g GrampusTrainTaskTemplate) CallRestartAPI(ctx *context.CreationContext) *
return response.SYSTEM_ERROR
}
form := ctx.Request
centerIds, bizErr := GetAvailableCenterIds(ctx.Spec, models.GetAvailableCenterIdOpts{
UserId: ctx.User.ID,
JobType: g.JobType,
HasInternet: form.HasInternet,
}, form.ComputeSource, form.ImageID, g.ClusterType)
if bizErr != nil {
return bizErr
}
req := entity.CreateTrainTaskRequest{
Name: form.JobName,
DisplayJobName: form.DisplayJobName,
@@ -193,16 +205,12 @@ func (g GrampusTrainTaskTemplate) CallRestartAPI(ctx *context.CreationContext) *
ImageUrl: strings.TrimSpace(form.ImageUrl),
Datasets: ctx.GetContainerDataArray(entity.ContainerDataset),
Code: ctx.GetContainerDataArray(entity.ContainerCode),
CenterID: ctx.Spec.GetAvailableCenterIds(models.GetAvailableCenterIdOpts{
UserId: ctx.User.ID,
JobType: g.JobType,
HasInternet: form.HasInternet,
}),
PreTrainModel: ctx.GetContainerDataArray(entity.ContainerPreTrainModel),
BootFile: form.BootFile,
OutPut: ctx.GetContainerDataArray(entity.ContainerOutPutPath),
Params: form.ParamArray,
Spec: ctx.Spec,
CenterID: centerIds,
PreTrainModel: ctx.GetContainerDataArray(entity.ContainerPreTrainModel),
BootFile: form.BootFile,
OutPut: ctx.GetContainerDataArray(entity.ContainerOutPutPath),
Params: form.ParamArray,
Spec: ctx.Spec,
},
},
}


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

@@ -692,7 +692,7 @@ func (g DefaultCreationHandler) NotifyCreation(ctx *context.CreationContext) *re

func (DefaultCreationHandler) CheckNotebookCount(ctx *context.CreationContext) *response.BizError {

if setting.NotebookStrategy.ClearEnabled && ctx.Request.JobType == models.JobTypeDebug {
if ctx.Request.JobType == models.JobTypeDebug {
count, err := models.GetNotebooksCountByUser(ctx.User.ID)
if err != nil {
log.Warn("can not get user notebook count", err)


+ 1
- 1
services/ai_task_service/task/super_compute_task.go View File

@@ -29,7 +29,7 @@ func init() {
RegisterTask(models.JobTypeSuperCompute, entity.C2Net, t)
}

func (g SuperComputeTaskTemplate) GetImages(computeSource models.ComputeSource) ([]entity.ClusterImage, bool, *response.BizError) {
func (g SuperComputeTaskTemplate) GetImages(computeSource models.ComputeSource, centerId ...string) ([]entity.ClusterImage, bool, *response.BizError) {
c := g.GetMyCluster()
if c == nil {
log.Error("Get cluster failed")


+ 8
- 4
services/ai_task_service/task/task_base.go View File

@@ -60,7 +60,7 @@ type AITaskTemplate interface {
GetDebugUrl(cloudbrainId int64, fileName ...string) (string, *response.BizError)
GetOperationProfile(cloudbrainId int64) (*entity.OperationProfile, *response.BizError)
GetResourceUsage(opts entity.GetResourceUsageOpts) (*entity.ResourceUsage, *response.BizError)
GetImages(computeSource models.ComputeSource) ([]entity.ClusterImage, bool, *response.BizError)
GetImages(computeSource models.ComputeSource, centerId ...string) ([]entity.ClusterImage, bool, *response.BizError)
GetSpecs(opts entity.GetSpecOpts) ([]*api.SpecificationShow, *response.BizError)
GetConfig(opts entity.AITaskConfigKey) *entity.AITaskBaseConfig
GetNodeInfo(cloudbrainId int64) ([]entity.AITaskNodeInfo, *response.BizError)
@@ -237,6 +237,10 @@ func (g DefaultAITaskTemplate) Stop(cloudbrainId int64) (*entity.AITaskBriefInfo
}

if err != nil {
log.Error("StopTask err.cloudbrainId=%d err=%v", cloudbrainId, err)
if models.IsErrCannotStopCreatingGrampusJob(err) {
return nil, response.CAN_NOT_STOP_CREATING_JOB
}
log.Error("StopTask err.cloudbrainId=%d err=%v", cloudbrainId, err)
return nil, response.NewBizError(err)
}
@@ -456,7 +460,7 @@ func (g DefaultAITaskTemplate) GetResourceUsage(opts entity.GetResourceUsageOpts
return res, nil
}

func (g DefaultAITaskTemplate) GetImages(computeSource models.ComputeSource) ([]entity.ClusterImage, bool, *response.BizError) {
func (g DefaultAITaskTemplate) GetImages(computeSource models.ComputeSource, centerId ...string) ([]entity.ClusterImage, bool, *response.BizError) {
c := g.GetMyCluster()
if c == nil {
log.Error("Get cluster failed")
@@ -470,12 +474,12 @@ func (g DefaultAITaskTemplate) GetImages(computeSource models.ComputeSource) ([]
images, customFlag, err = c.GetNotebookImages(entity.GetImageReq{
ComputeSource: computeSource,
JobType: g.JobType,
})
}, centerId...)
} else {
images, customFlag, err = c.GetTrainImages(entity.GetImageReq{
ComputeSource: computeSource,
JobType: g.JobType,
})
}, centerId...)
}
if err != nil {
log.Error("GetImages err.computeSource=%s err =%v", computeSource.Name, err)


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

@@ -55,11 +55,6 @@ func GetAITaskCreationInfo(req entity.GetAITaskCreationInfoReq) (*entity.Creatio

//生成任务名称
result.DisplayJobName = t.GetDisplayJobName(req.User.Name)
// 查询镜像列表
if images, canUseAll, err := t.GetImages(*req.ComputeSource); err == nil {
result.Images = images
result.CanUseAllImages = canUseAll
}
specsMap := make(map[string][]*structs.SpecificationShow, 0)
//查询有网资源规格
if specs, err := t.GetSpecs(entity.GetSpecOpts{
@@ -85,6 +80,12 @@ func GetAITaskCreationInfo(req entity.GetAITaskCreationInfoReq) (*entity.Creatio
specsMap["all"] = specs
}
result.Specs = specsMap
// 查询镜像列表
if images, canUseAll, err := t.GetImages(*req.ComputeSource); err == nil {
result.Images = images
result.CanUseAllImages = canUseAll
}

result.Config = entity.AITaskCreationConfig{
DatasetMaxSize: setting.DebugAttachSize * 1000 * 1000 * 1000,
}
@@ -96,3 +97,24 @@ func GetAITaskCreationInfo(req entity.GetAITaskCreationInfoReq) (*entity.Creatio
}
return result, nil
}

func GetAvailableImageInfoBySpec(req entity.GetAITaskCreationImageInfoReq) (*entity.ImageRequiredInfo, *response.BizError) {
result := &entity.ImageRequiredInfo{}
t, err := GetAITaskTemplate(req.JobType, req.ClusterType)

if err != nil {
log.Error("param error")
return nil, err
}
centerIds := req.Spec.GetAvailableCenterIds(models.GetAvailableCenterIdOpts{
UserId: req.UserID,
JobType: req.JobType,
})

if images, canUseAll, err := t.GetImages(*req.ComputeSource, centerIds...); err == nil {
result.Images = images
result.CanUseAllImages = canUseAll
}
return result, nil

}

+ 3
- 0
services/ai_task_service/task/task_extend.go View File

@@ -96,6 +96,7 @@ func getCloudBrainDatasetInfo4Local(uuid string, datasetname string, isNeedDown
link := ""
url := ""
isDelete := false
var size int64
attachment, err := models.GetAttachmentByUUID(uuidStr)
if err != nil {
log.Error("GetAttachmentByUUID failed:%v", err.Error())
@@ -106,6 +107,7 @@ func getCloudBrainDatasetInfo4Local(uuid string, datasetname string, isNeedDown
isDelete = true
} else {
name = attachment.Name
size = attachment.Size
dataset, err := models.GetDatasetByID(attachment.DatasetID)
if err != nil {
log.Error("GetDatasetByID failed:%v", err.Error())
@@ -128,6 +130,7 @@ func getCloudBrainDatasetInfo4Local(uuid string, datasetname string, isNeedDown
RepositoryLink: link,
IsDelete: isDelete,
UUID: uuidStr,
Size: size,
})
}
log.Info("dataset length=" + fmt.Sprint(len(datasetDownload)))


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

@@ -11,6 +11,7 @@ import (
"strings"

"code.gitea.io/gitea/entity"
"code.gitea.io/gitea/manager/client/grampus"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/convert"
"code.gitea.io/gitea/modules/git"
@@ -100,6 +101,7 @@ func buildAITaskInfo(task *models.Cloudbrain, creator *models.User, config *enti
ID: task.ID,
JobID: task.JobID,
Status: task.Status,
DetailedStatus: task.DetailedStatus,
JobType: task.JobType,
DisplayJobName: task.DisplayJobName,
FormattedDuration: task.TrainJobDuration,
@@ -240,6 +242,8 @@ func StopAITaskByJobNameFromRemote(task *models.Cloudbrain, queryFunc QueryListF
return nil
}

const DEFAULT_DETAILED_STATUS = "-"

func UpdateByQueryResponse(res *entity.QueryTaskResponse, task *models.Cloudbrain) error {
if res.JobId == "" {
return nil
@@ -260,6 +264,10 @@ func UpdateByQueryResponse(res *entity.QueryTaskResponse, task *models.Cloudbrai
newStatus := TransAITaskStatus(res.Status)

task.Status = newStatus
task.DetailedStatus = res.DetailedStatus
if res.DetailedStatus == "" || res.DetailedStatus == res.Status {
task.DetailedStatus = DEFAULT_DETAILED_STATUS
}
if res.StartedAt > 0 {
task.StartTime = res.StartedAt
}
@@ -722,6 +730,49 @@ func SyncAITaskStatus() {
}
}
}
func GetAvailableCenterIds(specification *models.Specification, opts models.GetAvailableCenterIdOpts, computeSource *models.ComputeSource,
imageId string, clusterType entity.ClusterType) ([]string, *response.BizError) {
centerIds := specification.GetAvailableCenterIds(opts)

if len(centerIds) == 0 || imageId == "" || clusterType != entity.C2Net {
return centerIds, nil
}

processType := computeSource.FullName
images, err := grampus.GetImages(processType, string(opts.JobType))
if err != nil {
log.Warn("can not get image info from grampus", err)
return centerIds, nil
}
var imageCenterIds []string
for _, image := range images.Infos {
if image.ID == imageId {
for _, centerInfo := range image.AICenterImage {
imageCenterIds = append(imageCenterIds, centerInfo.AICenterID)
}
break
}
}
if len(imageCenterIds) == 0 {
return centerIds, nil
}

var intersectionCenterIds []string
for _, centerId := range centerIds {
for _, imageCenterId := range imageCenterIds {
if centerId == imageCenterId {
intersectionCenterIds = append(intersectionCenterIds, centerId)
break
}
}
}
if len(intersectionCenterIds) == 0 {
return intersectionCenterIds, response.NO_CENTER_MATCH
}

return intersectionCenterIds, nil

}

func HandleNoJobIdAITasks() {
defer func() {


+ 1
- 0
services/cloudbrain/resource/resource_specification.go View File

@@ -290,6 +290,7 @@ func GetAndCheckSpec(userId int64, specId int64, opts models.FindSpecsOptions) (
return nil, nil
}
opts.SpecId = specId
opts.HasInternet = models.QueryAllSpecs
r, err := FindAvailableSpecs(userId, opts)
log.Info("FindAvailableSpecs result=%+v", r)
if err != nil {


+ 159
- 0
services/cloudbrain/statistic.go View File

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

import (
"code.gitea.io/gitea/modules/util"

"time"

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

var pageSize = 500

func CardStatistic() {
sevenDayStatistic()
thirtyDayStatistic()
daysAllStatistic()

}

func daysAllStatistic() {

daysStatistic(0, models.TypeAllDays)
}

func sevenDayStatistic() {

daysStatistic(7, models.TypeSevenDays)

}

func thirtyDayStatistic() {

daysStatistic(30, models.TypeThirtyDays)

}

func daysStatistic(days int, statisticType int) {
xpuCardStatisticMap, err := getStatisticInfoMap(days, statisticType)
if err != nil {
return
}

updateOrInsertStatisticRecord(xpuCardStatisticMap)

}

func updateOrInsertStatisticRecord(xpuCardStatisticMap map[string]*models.XPUInfoStatistic) {
for _, v := range xpuCardStatisticMap {
v.UsedCardHour = v.UsedDuration / 3600
err := models.UpdateOrInsertXPUInfoStatistic(v)
if err != nil {
log.Warn("update or insert xpu statistic err", err)
}
}
}

func getStatisticInfoMap(days int, statisticType int, beginTime ...int64) (map[string]*models.XPUInfoStatistic, error) {
endTimeUnix := time.Now().Unix()
beginTimeUnix := time.Now().AddDate(0, 0, -days).Unix()
if days == 0 {
beginTimeUnix = 1
}
if len(beginTime) > 0 {
beginTimeUnix = beginTime[0]
}

_, count, err := models.CloudbrainAll(&models.CloudbrainsOptions{
ListOptions: models.ListOptions{
Page: 1,
PageSize: 1,
},
NeedRepoInfo: false,
BeginTimeUnix: beginTimeUnix,
EndTimeUnix: endTimeUnix,
Type: -1,
AccCardsNum: -1,
})
if err != nil {
log.Error("Get job failed:", err)
return nil, err
}

xpuInfos, err := models.GetXPUInfos()
if err != nil {
log.Error("can not get XPU base info", err)
return nil, err
}

var xpuCardStatisticMap = make(map[string]*models.XPUInfoStatistic, len(xpuInfos))
var xpuCardStatisticUserMap = make(map[string]map[int64]struct{}, len(xpuInfos))
for _, xpuInfo := range xpuInfos {
xpuCardStatisticMap[xpuInfo.CardType] = &models.XPUInfoStatistic{
InfoID: xpuInfo.ID,
Type: statisticType,
UpdatedUnix: endTimeUnix,
}
xpuCardStatisticUserMap[xpuInfo.CardType] = make(map[int64]struct{}, 0)
}

totalPage := util.GetTotalPage(count, pageSize)

for i := 0; i < totalPage; i++ {

ciTasks, _, err := models.CloudbrainAll(&models.CloudbrainsOptions{
ListOptions: models.ListOptions{
Page: i + 1,
PageSize: pageSize,
},
NeedRepoInfo: false,
BeginTimeUnix: beginTimeUnix,
EndTimeUnix: endTimeUnix,
Type: -1,
AccCardsNum: -1,
})
if err != nil {
log.Error("Get job failed:", err)
return nil, err
}
err = models.LoadSpecs4CloudbrainInfo(ciTasks)
if err != nil {
log.Error("can not load spec info", err)
return nil, err
}

for _, task := range ciTasks {
if task.Spec != nil {
if v, ok := xpuCardStatisticMap[task.Spec.AccCardType]; ok {
v.TaskCount += 1
if calculateCardDuration(task.Cloudbrain) > 0 {
v.UsedDuration += calculateCardDuration(task.Cloudbrain)
}
if _, found := xpuCardStatisticUserMap[task.Spec.AccCardType][task.UserID]; !found {

v.UserCount += 1
xpuCardStatisticUserMap[task.Spec.AccCardType][task.UserID] = struct{}{}
}
}

}

}

}
return xpuCardStatisticMap, nil
}

func calculateCardDuration(task models.Cloudbrain) int64 {

cardNum := task.Spec.AccCardsNum

var workServerNumber int64
if task.WorkServerNumber >= 1 {
workServerNumber = int64(task.WorkServerNumber)
} else {
workServerNumber = 1
}
return workServerNumber * int64(cardNum) * task.Duration
}

+ 25
- 19
templates/admin/cloudbrain/list.tmpl View File

@@ -46,7 +46,7 @@
<div class="one wide column text center nowrap" style="width:6% !important;">
<span>{{$.i18n.Tr "repo.modelarts.cluster"}}</span>
</div>
<div class="two wide column text center nowrap" style="width: 6% !important;">
<div class="two wide column text center nowrap" style="width: 8% !important;">
<span>{{$.i18n.Tr "repo.modelarts.status"}}</span>
</div>
<div class="one wide column text center nowrap" style="width:6% !important;">
@@ -62,11 +62,11 @@
<span>{{$.i18n.Tr "repo.modelarts.computing_resources"}}</span>
</div>
<!-- 智算中心 -->
<div class="one wide column text center nowrap" style="width:8% !important;">
<div class="one wide column text center nowrap" style="width:7% !important;">
<span>{{$.i18n.Tr "repo.modelarts.ai_center"}}</span>
</div>
<!-- XPU类型 -->
<div class="one wide column text center nowrap" style="width:8% !important;">
<div class="one wide column text center nowrap" style="width:7% !important;">
<span>{{$.i18n.Tr "repo.modelarts.card_type"}}</span>
</div>
<div class="one wide column text center nowrap" style="width:4% !important;">
@@ -153,14 +153,16 @@
</div>
<!-- 任务状态 -->
<div class="two wide column text center nowrap"
style="width: 6% !important;">
style="width: 8% !important;">
<span class="job-status" id="{{$JobID}}"
data-repopath='{{.Repo.OwnerName}}/{{.Repo.Name}}{{if eq .JobType "DEBUG" "ONLINEINFERENCE" "HPC"}}{{if eq .Cloudbrain.Type 2}}/grampus/notebook{{else}}{{if eq .ComputeResource "CPU/GPU"}}/cloudbrain{{else}}/modelarts/notebook{{end}}{{end}}{{else if eq .JobType "INFERENCE"}}/modelarts/inference-job{{else if eq .JobType "TRAIN"}}/modelarts/train-job{{else if eq .JobType "BENCHMARK" "MODELSAFETY"}}/cloudbrain{{end}}'
data-jobid="{{$JobID}}" data-version="{{.VersionName}}"
data-cloudbrainid="{{.Cloudbrain.ID}}">
<span><i id="{{$JobID}}-icon" style="vertical-align: middle;"
class="{{.Status}}"></i><span id="{{$JobID}}-text"
style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span>
data-cloudbrainid="{{.Cloudbrain.ID}}" data-datamigrate='{{$.i18n.Tr "repo.migratingData"}}' data-centerpend='{{$.i18n.Tr "repo.centerPending"}}'>
<span>
<i id="{{$JobID}}-icon" style="vertical-align: middle;" class="{{.Status}}"></i>
<span id="{{$JobID}}-text" style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span>
{{if eq .Status "WAITING"}}<i id="{{$JobID}}-icon-detail" class="{{.DetailedStatus}}" style="vertical-align: middle;" title='{{$.i18n.Tr (printf "repo.%s" .DetailedStatus)}}'></i>{{end}}
</span>
</span>
</div>
<!-- 任务类型 -->
@@ -184,11 +186,11 @@
style="font-size: 12px;" title="{{.ComputeResource}}">{{if .ComputeResource}}{{.ComputeResource}}{{else}}--{{end}}</span>
</div>
<!-- 智算中心 -->
<div class="one wide column text center nowrap" style="width:8% !important;">
<div class="one wide column text center nowrap" style="width:7% !important;">
<span style="font-size: 12px;" id="cluster-{{$JobID}}" class="aicenter_{{.DisplayJobName}}_{{$JobID}}" title="{{if .AiCenter}}{{.AiCenter}}{{else}}--{{end}}">{{if .AiCenter}}{{.AiCenter}}{{else}}--{{end}}</span>
</div>
<!-- XPU类型 -->
<div class="one wide column text center nowrap" style="width:8% !important;">
<div class="one wide column text center nowrap" style="width:7% !important;">
<span style="font-size: 12px;" title="" class="card_type_{{.DisplayJobName}}_{{$JobID}}"></span>
</div>
<script>
@@ -329,7 +331,7 @@
<!-- 修改任务 -->
{{if and (eq .JobType "TRAIN") (not .FineTune)}}
<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{{else if eq .Cloudbrain.Type 0}}/cloudbrain/train-job{{else if eq .Cloudbrain.Type 2}}/grampus/train-job/{{ToLower .ComputeResource}}{{end}}/create?modify=true&id={{$JobID}}">
<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{{else if eq .Cloudbrain.Type 0}}/cloudbrain/train-job{{else if eq .Cloudbrain.Type 2}}/grampus/train-job/{{if eq .ComputeResource "CPU/GPU"}}gpu{{else}}{{ToLower .ComputeResource}}{{end}}{{end}}/create?modify=true&id={{$JobID}}'>
{{$.i18n.Tr "repo.modelarts.modify"}}
</a>
</div>
@@ -406,12 +408,16 @@
</div>
<!-- 任务状态 -->
<div class="two wide column text center nowrap"
style="width: 6% !important;">
<span class="job-status" id="{{$JobID}}" data-jobid="{{$JobID}}"
data-version="{{.VersionName}}" data-cloudbrainid="{{.Cloudbrain.ID}}">
<span><i id="{{$JobID}}-icon" style="vertical-align: middle;"
class="{{.Status}}"></i><span id="{{$JobID}}-text"
style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span>
style="width: 8% !important;">
<span class="job-status" id="{{$JobID}}"
data-repopath='{{.Repo.OwnerName}}/{{.Repo.Name}}{{if eq .JobType "DEBUG" "ONLINEINFERENCE" "HPC"}}{{if eq .Cloudbrain.Type 2}}/grampus/notebook{{else}}{{if eq .ComputeResource "CPU/GPU"}}/cloudbrain{{else}}/modelarts/notebook{{end}}{{end}}{{else if eq .JobType "INFERENCE"}}/modelarts/inference-job{{else if eq .JobType "TRAIN"}}/modelarts/train-job{{else if eq .JobType "BENCHMARK" "MODELSAFETY"}}/cloudbrain{{end}}'
data-jobid="{{$JobID}}" data-version="{{.VersionName}}"
data-cloudbrainid="{{.Cloudbrain.ID}}" data-datamigrate='{{$.i18n.Tr "repo.migratingData"}}' data-centerpend='{{$.i18n.Tr "repo.centerPending"}}'>
<span>
<i id="{{$JobID}}-icon" style="vertical-align: middle;" class="{{.Status}}"></i>
<span id="{{$JobID}}-text" style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span>
{{if eq .Status "WAITING"}}<i id="{{$JobID}}-icon-detail" class="{{.DetailedStatus}}" style="vertical-align: middle;" title='{{$.i18n.Tr (printf "repo.%s" .DetailedStatus)}}'></i>{{end}}
</span>
</span>
</div>
<!-- 任务类型 -->
@@ -435,12 +441,12 @@
style="font-size: 12px;" title="{{.ComputeResource}}">{{if .ComputeResource}}{{.ComputeResource}}{{else}}--{{end}}</span>
</div>
<!-- 智算中心 -->
<div class="one wide column text center nowrap" style="width:8% !important;">
<div class="one wide column text center nowrap" style="width:7% !important;">
<span
style="font-size: 12px;">{{if .AiCenter}}{{.AiCenter}}{{else}}--{{end}}</span>
</div>
<!-- XPU类型 -->
<div class="one wide column text center nowrap" style="width:8% !important;">
<div class="one wide column text center nowrap" style="width:7% !important;">
<span style="font-size: 12px;" title="{{.CardType}}">
{{if .CardType}}{{.CardType}}{{else}}--{{end}}
</span>


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

@@ -54,6 +54,7 @@
<!--<a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a>-->
<a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a>
<a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a>
<!--<a class="item" href="{{AppSubUrl}}/explore/domestic"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "explore.domestic_computing_power"}}</span></a>-->
{{if .IsOperator}}
{{/* <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> */}}
<a class="item" href="{{AppSubUrl}}/kanban/index.html" target="_blank" rel="opener">{{.i18n.Tr "explore.data_analysis"}}</a>
@@ -102,6 +103,7 @@
<!--<a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a>-->
<a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a>
<a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a>
<!--<a class="item" href="{{AppSubUrl}}/explore/domestic"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "explore.domestic_computing_power"}}</span></a>-->
{{if .IsOperator}}
{{/* <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> */}}
<a class="item" href="{{AppSubUrl}}/kanban/index.html" target="_blank" rel="opener">{{.i18n.Tr "explore.data_analysis"}}</a>


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

@@ -51,6 +51,7 @@
<!--<a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a>-->
<a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a>
<a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a>
<!--<a class="item" href="{{AppSubUrl}}/explore/domestic"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "explore.domestic_computing_power"}}</span></a>-->
{{if .IsOperator}}
{{/* <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> */}}
<a class="item" href="{{AppSubUrl}}/kanban/index.html" target="_blank" rel="opener">{{.i18n.Tr "explore.data_analysis"}}</a>
@@ -96,6 +97,7 @@
<!--<a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a>-->
<a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a>
<a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a>
<!--<a class="item" href="{{AppSubUrl}}/explore/domestic"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "explore.domestic_computing_power"}}</span></a>-->
{{if .IsOperator}}
{{/* <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> */}}
<a class="item" href="{{AppSubUrl}}/kanban/index.html" target="_blank" rel="opener">{{.i18n.Tr "explore.data_analysis"}}</a>


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

@@ -43,6 +43,7 @@
<!--<a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a>-->
<a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a>
<a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a>
<!--<a class="item" href="{{AppSubUrl}}/explore/domestic"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "explore.domestic_computing_power"}}</span></a>-->
{{if .IsOperator}}
{{/* <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> */}}
<a class="item" href="{{AppSubUrl}}/kanban/index.html" target="_blank" rel="opener">{{.i18n.Tr "explore.data_analysis"}}</a>
@@ -90,6 +91,7 @@
<!--<a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a>-->
<a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a>
<a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a>
<!--<a class="item" href="{{AppSubUrl}}/explore/domestic"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "explore.domestic_computing_power"}}</span></a>-->
{{if .IsOperator}}
{{/* <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> */}}
<a class="item" href="{{AppSubUrl}}/kanban/index.html" target="_blank" rel="opener">{{.i18n.Tr "explore.data_analysis"}}</a>


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

@@ -53,6 +53,7 @@
<!--<a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a>-->
<a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a>
<a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a>
<!--<a class="item" href="{{AppSubUrl}}/explore/domestic"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "explore.domestic_computing_power"}}</span></a>-->
{{if .IsOperator}}
{{/* <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> */}}
<a class="item" href="{{AppSubUrl}}/kanban/index.html" target="_blank" rel="opener">{{.i18n.Tr "explore.data_analysis"}}</a>
@@ -100,6 +101,7 @@
<!--<a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a>-->
<a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a>
<a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a>
<!--<a class="item" href="{{AppSubUrl}}/explore/domestic"><span class="menu-new" style="margin-right: 20px;">{{.i18n.Tr "explore.domestic_computing_power"}}</span></a>-->
{{if .IsOperator}}
{{/* <a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> */}}
<a class="item" href="{{AppSubUrl}}/kanban/index.html" target="_blank" rel="opener">{{.i18n.Tr "explore.data_analysis"}}</a>


+ 7
- 0
templates/explore/domestic.tmpl View File

@@ -0,0 +1,7 @@
{{template "base/head" .}}
<link rel="stylesheet" href="{{StaticUrlPrefix}}/css/vp-explore-domestic.css?v={{MD5 AppVer}}"/>
<div>
<div id="__vue-root"></div>
</div>
<script src="{{StaticUrlPrefix}}/js/vp-explore-domestic.js?v={{MD5 AppVer}}"></script>
{{template "base/footer" .}}

+ 92
- 207
templates/repo/datasets/dirs/dir_preview.tmpl
File diff suppressed because it is too large
View File


+ 18
- 12
templates/repo/datasets/dirs/index.tmpl View File

@@ -1,22 +1,33 @@
<style>
form {margin-block-end: 0;}
form {margin-block-end: 0;}
#file_path_container .section {
color: rgb(50, 145, 248);
}
</style>
<div style="background:#fff">
{{template "base/head" .}}
<div class="repository dataset dir-list view">
{{template "repo/header" .}}
<script>
var DATASET_DATA = {
csrf: {{.CsrfToken}},
repoLink: {{$.RepoLink}},
link: {{$.Link}},
uuid: {{$.Uuid}},
type: {{.Type}},
path: {{.Path}},
isDir: {{.Dirs}},
};
</script>
<div>
<form class="ui container">
<div class="ui stackable grid {{if .Error}}hide{{end}}" id="dir-content">
<div class="row">
<div class="row" style="padding: 6px 0;">
<div class="column sixteen wide">
<div class="ui breadcrumb">
{{ range $index, $item := .Path }}<a class="section" href='{{$.Link}}/?parentDir={{if gt $index 0}}{{DatasetPathJoin $.Path $index "/"}}{{else}}{{end}}'>{{ $item }}</a><div class="divider"> / </div>{{ end }}
</div>
<div id="file_path_container" style="display:flex;flex-wrap:wrap;min-height:20px" class="ui breadcrumb "></div>
</div>
</div>
</div>
<div class="ui grid">
<div class="row" style="padding-top: 0.5rem;padding-bottom: 0;">
<div class="ui sixteen wide column">
@@ -27,12 +38,7 @@ form {margin-block-end: 0;}
</div>
</div>
</form>
</div>
</div>
</div>
</div>




{{template "base/footer" .}}

+ 16
- 10
templates/user/dashboard/cloudbrains.tmpl View File

@@ -141,10 +141,12 @@
data-repopath='{{.Repo.OwnerName}}/{{.Repo.Name}}{{if eq .JobType "DEBUG" "ONLINEINFERENCE" "HPC"}}{{if eq .Cloudbrain.Type 2}}/grampus/notebook{{else}}{{if eq .ComputeResource "CPU/GPU"}}/cloudbrain{{else}}/modelarts/notebook{{end}}{{end}}{{else if eq .JobType "INFERENCE"}}{{if eq .ComputeResource "CPU/GPU"}}/cloudbrain{{else}}/modelarts{{end}}/inference-job{{else if eq .JobType "TRAIN"}}{{if eq .ComputeResource "NPU"}}/modelarts/train-job{{else}}/cloudbrain/train-job{{end}}{{else if eq .JobType "BENCHMARK" "MODELSAFETY"}}/cloudbrain{{end}}'
data-jobid="{{$JobID}}" data-version="{{.VersionName}}"
data-cloudbrainid="{{.Cloudbrain.ID}}"
data-bootfile="{{.BootFile}}">
<span><i id="{{$JobID}}-icon" style="vertical-align: middle;"
class="{{.Status}}"></i><span id="{{$JobID}}-text"
style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span>
data-bootfile="{{.BootFile}}" data-datamigrate='{{$.i18n.Tr "repo.migratingData"}}' data-centerpend='{{$.i18n.Tr "repo.centerPending"}}'>
<span>
<i id="{{$JobID}}-icon" style="vertical-align: middle;" class="{{.Status}}"></i>
<span id="{{$JobID}}-text" style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span>
{{if eq .Status "WAITING"}}<i id="{{$JobID}}-icon-detail" class="{{.DetailedStatus}}" style="vertical-align: middle;" title='{{$.i18n.Tr (printf "repo.%s" .DetailedStatus)}}'></i>{{end}}
</span>
</span>
</div>
<!-- 任务类型 -->
@@ -299,7 +301,7 @@
<!-- 修改任务 -->
{{if and (eq .JobType "TRAIN") (not .FineTune)}}
<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{{else if eq .Cloudbrain.Type 0}}/cloudbrain/train-job{{else if eq .Cloudbrain.Type 2}}/grampus/train-job/{{ToLower .ComputeResource}}{{end}}/create?modify=true&id={{$JobID}}">
<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{{else if eq .Cloudbrain.Type 0}}/cloudbrain/train-job{{else if eq .Cloudbrain.Type 2}}/grampus/train-job/{{if eq .ComputeResource "CPU/GPU"}}gpu{{else}}{{ToLower .ComputeResource}}{{end}}{{end}}/create?modify=true&id={{$JobID}}'>
{{$.i18n.Tr "repo.modelarts.modify"}}
</a>
</div>
@@ -377,11 +379,15 @@
<!-- 任务状态 -->
<div class="two wide column text center nowrap"
style="padding-left: 2.2rem !important; width: 8% !important;">
<span class="job-status" id="{{$JobID}}" data-jobid="{{$JobID}}"
data-version="{{.VersionName}}" data-cloudbrainid="{{.Cloudbrain.ID}}">
<span><i id="{{$JobID}}-icon" style="vertical-align: middle;"
class="{{.Status}}"></i><span id="{{$JobID}}-text"
style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span>
<span class="job-status" id="{{$JobID}}"
data-repopath='{{.Repo.OwnerName}}/{{.Repo.Name}}{{if eq .JobType "DEBUG" "ONLINEINFERENCE" "HPC"}}{{if eq .Cloudbrain.Type 2}}/grampus/notebook{{else}}{{if eq .ComputeResource "CPU/GPU"}}/cloudbrain{{else}}/modelarts/notebook{{end}}{{end}}{{else if eq .JobType "INFERENCE"}}/modelarts/inference-job{{else if eq .JobType "TRAIN"}}/modelarts/train-job{{else if eq .JobType "BENCHMARK" "MODELSAFETY"}}/cloudbrain{{end}}'
data-jobid="{{$JobID}}" data-version="{{.VersionName}}"
data-cloudbrainid="{{.Cloudbrain.ID}}" data-datamigrate='{{$.i18n.Tr "repo.migratingData"}}' data-centerpend='{{$.i18n.Tr "repo.centerPending"}}'>
<span>
<i id="{{$JobID}}-icon" style="vertical-align: middle;" class="{{.Status}}"></i>
<span id="{{$JobID}}-text" style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span>
{{if eq .Status "WAITING"}}<i id="{{$JobID}}-icon-detail" class="{{.DetailedStatus}}" style="vertical-align: middle;" title='{{$.i18n.Tr (printf "repo.%s" .DetailedStatus)}}'></i>{{end}}
</span>
</span>
</div>
<!-- 任务类型 -->


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

@@ -13,16 +13,23 @@ export default async function initCloudrain() {

let debug_button = $(".cloudbrain_debug").data("debug");
let debug_again_button = $(".cloudbrain_debug").data("debug-again");
let timeid = window.setInterval(loadJobStatus, 15000);
let timeidShow = window.setInterval(loadShowJobStatus, 15000);
let timeid
let timeidShow
if (document.getElementsByClassName('job-status').length!==0) {
timeid = window.setInterval(loadJobStatus, 15000);
timeidShow = window.setInterval(loadShowJobStatus, 15000);
}
$(document).ready(loadJobStatus);
$(document).ready(loadShowJobStatus);
function loadJobStatus() {
let flagStopInterval = 0
$(".job-status").each((index, job) => {
const ID = job.dataset.jobid;
const cloudbrainID = job.dataset.cloudbrainid;
if (!ID) return;
const repoPath = job.dataset.repopath;
const dataMigrate = job.dataset.datamigrate
const centerPend = job.dataset.centerpend
// const computeResource = job.dataset.resource
const versionname = job.dataset.version;
const bootfile = job.dataset.bootfile;
@@ -49,6 +56,10 @@ export default async function initCloudrain() {
"CHECK_FAILED",
];
if (finalState.includes(status_text)) {
flagStopInterval++
if (flagStopInterval === $(".job-status").length) {
clearInterval(timeid)
}
return;
}
// const diffResource = computeResource == "NPU" ? 'modelarts/notebook' : 'cloudbrain'
@@ -59,9 +70,20 @@ export default async function initCloudrain() {
const status = data.JobStatus;
const duration = data.JobDuration;
const aiCenter = data.AiCenter || '--'
const detailStatus = data.DetailedStatus
$("#duration-" + ID).text(duration);
data.AiCenter != undefined && $("#cluster-" + ID).text(aiCenter);
data.AiCenter != undefined && $("#" + versionname + "-ai_center").text(data.AiCenter);
if ( (detailStatus === 'dataMigrating' || detailStatus === 'centerPending') && status==='WAITING') {
if (document.getElementById(`${ID}-icon-detail`)) {
document.getElementById(`${ID}-icon-detail`).remove()
}
$("#" + ID + "-text").parent().append(`<i id="${ID}-icon-detail" class="${detailStatus}" style="vertical-align: middle;" title="${detailStatus === 'dataMigrating'? dataMigrate:centerPend}"></i>`)
} else {
if (document.getElementById(`${ID}-icon-detail`)) {
document.getElementById(`${ID}-icon-detail`).remove()
}
}
if (status != status_text) {
$("#" + ID + "-icon")
.removeClass()
@@ -209,6 +231,7 @@ export default async function initCloudrain() {
"CREATED_FAILED",
].includes(status)
) {
clearInterval(timeidShow)
return;
}
let stopArray = [
@@ -400,6 +423,14 @@ export default async function initCloudrain() {
$("#ai-stop-" + ID).removeClass("blue");
$("#ai-stop-" + ID).addClass("disabled");
refreshStatus(version_name, ID, repoPath, cloudbrainID);
} else {
$(".alert")
.html(data.error_msg)
.removeClass("alert-success")
.addClass("alert-danger")
.show()
.delay(2000)
.fadeOut();
}
}).fail(function (err) {
console.log(err);
@@ -427,6 +458,19 @@ export default async function initCloudrain() {
.removeClass("disabled")
.addClass("blue");
}
const detailStatus = data.DetailedStatus
const dataMigrate = $(`${ID}`).data('datamigrate')
const centerPend = $(`${ID}`).data('centerpend')
if ((detailStatus === 'dataMigrating' || detailStatus === 'centerPending') && data.JobStatus==='WAITING') {
if (document.getElementById(`${ID}-icon-detail`)) {
document.getElementById(`${ID}-icon-detail`).remove()
}
$("#" + ID + "-text").parent().append(`<i id="${ID}-icon-detail" class="${detailStatus}" style="vertical-align: middle;" title="${detailStatus === 'dataMigrating'? dataMigrate:centerPend}"></i>`)
} else {
if (document.getElementById(`${ID}-icon-detail`)) {
document.getElementById(`${ID}-icon-detail`).remove()
}
}
}).fail(function (err) {
console.log(err);
});


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

@@ -2457,7 +2457,7 @@ function searchRepositories() {
$searchRepoBox.search({
minCharacters: 2,
apiSettings: {
url: `${AppSubUrl}/api/v1/repos/search?q={query}&uid=${$searchRepoBox.data(
url: `${AppSubUrl}/api/v1/repos/search?_csrf=${csrf}&q={query}&uid=${$searchRepoBox.data(
"uid"
)}`,
onResponse(response) {
@@ -2711,7 +2711,7 @@ function initTemplateSearch() {
const changeOwner = function () {
$("#repo_template_search").dropdown({
apiSettings: {
url: `${AppSubUrl}/api/v1/repos/search?q={query}&template=true&priority_owner_id=${$(
url: `${AppSubUrl}/api/v1/repos/search?_csrf=${csrf}&q={query}&template=true&priority_owner_id=${$(
"#uid"
).val()}`,
onResponse(response) {


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

@@ -319,6 +319,23 @@ i.INFO {
.i-bg-orange {
background-position: -495px -51px;
}
.dataMigrating{
display: inline-block;
width: 18px;
height: 18px;
margin-left: 8px;
background: url("/img/icons.svg");
background-position: -56px -52px;
}
.centerPending{
display: inline-block;
width: 18px;
height: 18px;
margin-left: 8px;
background: url("/img/icons.svg");
background-position: -511px -52px;

}
.FAILED,
.START_FAILED,
.DELETED,


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

@@ -15,6 +15,22 @@ export const getAiTaskPrepareInfo = (params) => {
});
}

// 由资源规格查询可用镜像
// params: repoOwnerName, repoName, job_type,compute_source,cluster_type,spec_id
export const getAiTaskImgesBySpec = (params) => {
return service({
url: `/api/v1/${params.repoOwnerName}/${params.repoName}/ai_task/creation/image_by_spec`,
method: 'get',
params: {
job_type: params.jobType,
compute_source: params.computeSource,
cluster_type: params.clusterType,
spec_id: params.spec,
has_internet: params.hasInternet,
},
});
}

// 创建AI任务
export const createAiTask = (data) => {
return service({


+ 14
- 0
web_src/vuepages/apis/modules/domestic.js View File

@@ -0,0 +1,14 @@
import service from "../service";

// 获取国产算力卡使用情况相关数据
// params - type-all|7|30, category-card|user|task
export const getDomesticCardData = (params) => {
return service({
url: `/api/v1/cloudbrainboard/card_data`,
method: "get",
params: {
type: params.type,
category: params.category,
}
});
};

+ 1
- 0
web_src/vuepages/components/BaseDialog.vue View File

@@ -63,6 +63,7 @@ export default {
this.$emit("update:visible", false);
},
},
mounted() {},
};
</script>
<style scoped lang="less">


+ 85
- 0
web_src/vuepages/components/cloudbrain/DialogTips.vue View File

@@ -0,0 +1,85 @@

<template>
<BaseDialog :visible="visible" :title="onlineInferTitle" top="30vh" :show-close="showClose">
<div class="tipsWrapper" style="margin:2rem;">
<ul>
<li class="mr-1">{{$t('cloudbrainObj.dialogTips.tips1')}}</li>
<li class="mr-1">{{$t('cloudbrainObj.dialogTips.tips2')}}<br>
<pre style="padding: 0 4rem;white-space: pre-line;">
<span class="cl-red">""" ********************************** """</span>
<span class="cl-333">from</span> fastapi <span class="cl-333">import</span> FastAPI
<span class="cl-333">import</span> os
<span class="cl-333">import</span class="cl-333"> gradio <span>import</span> gr
app = FastAPI()
<span class="cl-red">""" ********************************** """</span>
<span class="cl-red">"""{{$t('cloudbrainObj.dialogTips.tips3')}}"""</span>
<span class="cl-red">"""**********************************"""</span>
<span class="cl-red">"""*******{{$t('cloudbrainObj.dialogTips.tips10')}}*******"""</span>
<span class="cl-red">"""**********************************"""</span>
<span style="color: #998;font-style: italic;"> #demo.launch()</span>
<span class="cl-red">"""{{$t('cloudbrainObj.dialogTips.tips4')}}""""</span>
<span class="cl-red">app = gr.mount_gradio_app(app, demo, path=os.getenv('OPENI_GRADIO_URL'))</span>
</pre>
</li>
<li class="mr-1">{{$t('cloudbrainObj.dialogTips.tips5')}}</li>
<li class="mr-1">{{$t('cloudbrainObj.dialogTips.tips61')}}<a href="https://openi.pcl.ac.cn/OpenIOSSG/Online-Inference_Example" target="_blank">{{$t('cloudbrainObj.dialogTips.tips62')}}</a></li>
</ul>
<div class="btn-wrapper">
<el-checkbox v-model="checked" class="mr-1">{{$t('cloudbrainObj.dialogTips.tips7')}}</el-checkbox>
<el-button type="primary" @click="closeDialog">{{$t('cloudbrainObj.dialogTips.tips8')}}</el-button>
</div>
</div>
</BaseDialog>
</template>

<script>
import BaseDialog from '~/components/BaseDialog.vue';
export default {
name: "DialogTips",
components:{
BaseDialog
},
props: {
visible: { type: Boolean, default: false },
},
data() {
return {
onlineInferTitle:this.$t('cloudbrainObj.dialogTips.tips9'),
checked:false,
showClose:false,
}
},
methods:{
closeDialog(){
if(this.checked){
localStorage.setItem("isCloseOnlineTips",true)
}else{
localStorage.setItem("isCloseOnlineTips",false)
}
this.$emit("closeDialog");
}
},
mounted() {
},
}
</script>

<style scoped lang="less">
.mr-1{
margin: 1rem;
}
.cl-red{
color: red;
}
.cl-333{
color: #333;
font-weight: 700;
}
.btn-wrapper{
display: flex;
justify-content: end;
align-items: center;
}
</style>

+ 41
- 1
web_src/vuepages/components/cloudbrain/ImageSelectV2.vue View File

@@ -14,15 +14,21 @@

<script>

import { getAiTaskImgesBySpec } from '~/apis/modules/cloudbrain';
export default {
name: 'ImageSelectV2',
props: {
configs: { type: Object, required: true, },
value: { type: Object, required: true },
images: { type: Array, required: true, },
spec: { type: String, required: true, },
networkType: { type: String, required: true },
required: { type: Boolean, default: true },
},
data() {
return {
repoOwnerName: location.pathname.split('/')[1],
repoName: location.pathname.split('/')[2],
currentValue: '',
errStatus: false,
};
@@ -35,7 +41,41 @@ export default {
newVal = newVal === undefined ? {} : newVal;
this.currentValue = (newVal.image_id || '').toString();
}
}
},
spec: {
immediate: true,
handler(newVal) {
const imagev2Cfg = this.configs?.form?.imagev2;
if (imagev2Cfg && imagev2Cfg.relatedSpec) {
if (!newVal) {
this.$emit('changeImages', []);
} else {
let networkType = 0; // all
if (this.networkType == 'no_internet') {
networkType = 1;
} else if (this.networkType == 'has_internet') {
networkType = 2;
}
getAiTaskImgesBySpec({
repoOwnerName: this.repoOwnerName,
repoName: this.repoName,
jobType: this.configs.taskType,
computeSource: this.configs.computerResouce,
clusterType: this.configs.clusterType,
spec: newVal,
hasInternet: networkType,
}).then(res => {
const data = res.data;
if (data.code == 0) {
this.$emit('changeImages', data?.data?.images || []);
}
}).catch(err => {
console.log(err);
})
}
}
}
},
},
methods: {
check() {


+ 15
- 0
web_src/vuepages/langs/config/en-US.js View File

@@ -669,7 +669,22 @@ const en = {
chartTime: 'Time(min)',
scrollToTop: 'Scroll to top',
scrollToBottom: 'Scroll to bottom',
migratingData: 'Data migration in progress',
centerPending: 'Queuing in sub centers',

dialogTips: {
tips1: "The platform does not directly provide external ports such as 7860 for external services, and can only use FastAPI to forward to the specified URL exposed to the outside world (environment variable can be obtained: os. getenv ('OPENI_GRADIO_URL ') to provide services.",
tips2: 'We need to make a simple adjustment to the way the original Gradio code started the webui, only slightly modifying the original code at the beginning and end. The platform will use the FastAPI method to start the webui service.',
tips3: 'The above is the code required for the fixed startup of the Gradio platform',
tips4: "The following is the demo.launch() startup method for replacing the required code for the platform's fixed needs",
tips5: 'The code needs to be confirmed in the debugging environment to ensure that there are no errors in the original graphical code running, so as to ensure that the code can run properly. Otherwise, online reasoning will directly display a successful or failed state, as there are currently no message prompts for code running errors in online reasoning.',
tips61: 'Detailed usage methods can be found in ',
tips62: 'the code repository',
tips7: "Don't prompt again",
tips8: 'Close',
tips9: 'OpenI Online Inference Deployment Requirements',
tips10: 'Your original gradio webui code',
}

},
superComputeObj: {


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

@@ -685,7 +685,22 @@ const zh = {
chartTime: '时间(min)',
scrollToTop: '滚动到顶部',
scrollToBottom: '滚动到底部',
migratingData: '数据迁移中',
centerPending: '分中心排队中',

dialogTips: {
tips1: "平台没有对外直接提供端口如:7860 对外提供服务,只能使用fastapi转发到对外暴露的指定的URL(环境变量可获取:os.getenv('OPENI_GRADIO_URL'))提供服务。",
tips2: '需要简单的调整原先gradio代码启动webui的方式,仅在开头和结尾稍微修改下原始代码,平台会使用fastapi方式启动webui服务。',
tips3: '以上为gradio方式平台启动固定需要的代码',
tips4: '以下为平台固定需要的代码 替换gradio的demo.launch()启动方式',
tips5: '因为在线推理目前没有代码运行错误的消息提示反馈,代码需要在调试环境下先确定原先gradio代码运行没有错误,确保代码能跑起来,不然在线推理会直接呈现succeeded或failed状态。',
tips61: '详细使用方法可查看',
tips62:'使用样例代码仓',
tips7: '不再提示',
tips8: '关闭',
tips9: 'OpenI在线推理部署须知',
tips10: '您的原始gradio webui代码',
}


},


+ 2
- 2
web_src/vuepages/pages/cloudbrain/configs.js View File

@@ -113,7 +113,7 @@ export const CreatePageConfigs = {
taskDescr: { required: false, },
branchName: { required: true, },
model: { required: false, multiple: true },
imagev2: { required: true },
imagev2: { required: true, relatedSpec: true },
dataset: { required: false, type: 1, useExceedSize: true },
networkType: { required: true },
spec: { required: true },
@@ -324,7 +324,7 @@ export const CreatePageConfigs = {
taskDescr: { required: false, },
branchName: { required: true, },
model: { required: false, multiple: false },
imagev2: { required: true },
imagev2: { required: true, relatedSpec: true },
bootFile: { required: true, sampleUrl: 'https://openi.pcl.ac.cn/OpenIOSSG/MNIST_Example/src/branch/master/train_for_c2net.py' },
dataset: { required: true, type: 1 },
runParameters: { required: false },


+ 38
- 8
web_src/vuepages/pages/cloudbrain/create/index.vue View File

@@ -26,6 +26,12 @@
<div class="main-title">{{ $t('cloudbrainObj.basicInfo') }}:</div>
<FormTop ref="formTopRef" :repoOwnerName="repoOwnerName" :repoName="repoName" :configs="pageCfg"
:queueNum="queueNum"></FormTop>
<NetworkType ref="networkTypeRef" v-if="formCfg.networkType" v-model="state.networkType"></NetworkType>
<SpecSelect ref="specRef" v-if="formCfg.spec" v-model="state.spec" :required="formCfg.spec.required"
:configs="specConfigs" :workServerNum="state.workServerNum" :networkType="state.networkType"></SpecSelect>
<WorkServerNum ref="workServerNumRef" v-if="formCfg.workServerNum && workServerNumList.length > 1"
v-model="state.workServerNum" :required="formCfg.workServerNum.required" :data="workServerNumList">
</WorkServerNum>
<TaskName ref="taskNameRef" v-if="formCfg.taskName" v-model="state.taskName" autofocus
:required="formCfg.taskName.required" :userName="repoOwnerName">
</TaskName>
@@ -49,6 +55,7 @@
:required="formCfg.imagev1.required" :type="formCfg.imagev1.type != undefined ? formCfg.imagev1.type : 0">
</ImageSelectV1>
<ImageSelectV2 ref="imagev2Ref" v-if="formCfg.imagev2" v-model="state.image" :images="imageList"
:configs="pageCfg" :spec="state.spec" :networkType="state.networkType" @changeImages="changeImages"
:required="formCfg.imagev2.required">
</ImageSelectV2>
<BootFile ref="bootFileRef" v-if="formCfg.bootFile" v-model="state.bootFile"
@@ -60,12 +67,6 @@
<RunParameters ref="runParametersRef" v-if="formCfg.runParameters" v-model="state.runParameters"
:required="formCfg.runParameters.required">
</RunParameters>
<NetworkType ref="networkTypeRef" v-if="formCfg.networkType" v-model="state.networkType"></NetworkType>
<SpecSelect ref="specRef" v-if="formCfg.spec" v-model="state.spec" :required="formCfg.spec.required"
:configs="specConfigs" :workServerNum="state.workServerNum" :networkType="state.networkType"></SpecSelect>
<WorkServerNum ref="workServerNumRef" v-if="formCfg.workServerNum && workServerNumList.length > 1"
v-model="state.workServerNum" :required="formCfg.workServerNum.required" :data="workServerNumList">
</WorkServerNum>
<div class="form-row" v-if="this.isModifyTask && (pageCfg.modify && pageCfg.modify.showIsContinue)">
<div class="title"></div>
<div class="content">
@@ -91,9 +92,11 @@
</div>
</div>
</div>
</div>
</div>
<LoadingMask :loading="maskLoading" :content="maskLoadingContent"></LoadingMask>
<DialogTips :visible="visible" @closeDialog="visible=false"></DialogTips>
</div>
</template>

@@ -113,6 +116,7 @@ import NetworkType from '~/components/cloudbrain/NetworkType.vue';
import SpecSelect from '~/components/cloudbrain/SpecSelect.vue';
import WorkServerNum from '~/components/cloudbrain/WorkServerNum.vue';
import AlgBechmarkType from '~/components/cloudbrain/AlgBechmarkType.vue';
import DialogTips from '~/components/cloudbrain/DialogTips.vue';
import LoadingMask from '~/components/cloudbrain/LoadingMask.vue';

import { getCreatePageConfigs } from '../configs';
@@ -168,14 +172,16 @@ export default {
datasetSize: 0,
isModifyTask: false,
modeifyTaskId: '',
oldTask: {},
noSpecFlag: false,
visible:false
};
},
components: {
FormTop, TaskName, TaskDescr, BranchName, BootFile, AIEngineSelect, ImageSelectV1, ImageSelectV2,
ModelSelect, DatasetSelect, RunParameters, NetworkType, SpecSelect, WorkServerNum,
AlgBechmarkType,
LoadingMask
LoadingMask, DialogTips
},
methods: {
submit() {
@@ -310,6 +316,7 @@ export default {
if (task.description) {
this.state.taskDescr = task.description;
}
this.oldTask = task;
if (this.formCfg['imagev1'] && task.image_url) {
this.state.image_url = task.image_url;
}
@@ -422,6 +429,23 @@ export default {
console.log(err);
});
},
changeImages(images) {
this.imageList = images || [];
let image = this.imageList[0];
if (this.isModifyTask && this.modeifyTaskId && this.oldTask.image_id) {
const matchImage = this.imageList.filter(item => item.image_id == this.oldTask.image_id)[0];
if (matchImage) {
image = matchImage;
}
}
if (image) {
this.state.image.image_id = image.image_id;
this.state.image.image_name = image.image_name;
} else {
this.state.image.image_id = '';
this.state.image.image_name = '';
}
},
transformTreeData(data) {
for (let i = 0, iLen = data.length; i < iLen; i++) {
const dataI = data[i];
@@ -460,6 +484,7 @@ export default {
this.cancelUrl = urlParams.backurl;
}
this.pageCfg = configs;
this.formCfg = this.pageCfg.form || {};
if (!configs.taskType || !configs.clusterType || !configs.computerResouce) {
console.log(`page configs error.`);
@@ -545,7 +570,12 @@ export default {
console.log(err);
});
},
mounted() { },
mounted() {
const isCloseOnlineTips = localStorage.getItem("isCloseOnlineTips")
if(this.pageCfg.taskType==="ONLINEINFERENCE" && !JSON.parse(isCloseOnlineTips)){
this.visible = true
}
},
beforeDestroy() { },
};
</script>


+ 5
- 1
web_src/vuepages/pages/cloudbrain/detail/index.vue View File

@@ -22,7 +22,11 @@
<div class="title-l">
<span class="task-create-time">{{ item.task.createTimeStr }}</span>
<span class="task-status">
<span>{{ $t('status') }}:</span><i :class="item.task.status"></i><span>{{ item.task.status }}</span>
<span>{{ $t('status') }}:</span>
<i :class="item.task.status"></i>
<span>{{ item.task.status }}</span>
<i v-if="item.task.detailed_status==='dataMigrating' && item.task.status==='WAITING'" :class="item.task.detailed_status" :title="$t('cloudbrainObj.migratingData')"></i>
<i v-if="item.task.detailed_status==='centerPending' && item.task.status==='WAITING'" :class="item.task.detailed_status" :title="$t('cloudbrainObj.centerPending')"></i>
</span>
<span class="task-duration">
<span>{{ $t('cloudbrainObj.runDuration') }}:</span><span>{{ item.task.formatted_duration }}</span>


+ 2
- 0
web_src/vuepages/pages/cloudbrain/list/index.vue View File

@@ -43,6 +43,8 @@
<div class="status-wrap">
<i :class="scope.row.task.status"></i>
<span>{{ scope.row.task.status }}</span>
<i v-if="scope.row.task.detailed_status==='dataMigrating' && scope.row.task.status==='WAITING'" :class="scope.row.task.detailed_status" :title="$t('cloudbrainObj.migratingData')"></i>
<i v-if="scope.row.task.detailed_status==='centerPending' && scope.row.task.status==='WAITING'" :class="scope.row.task.detailed_status" :title="$t('cloudbrainObj.centerPending')"></i>
</div>
</template>
</el-table-column>


+ 833
- 0
web_src/vuepages/pages/explore/domestic/index.vue View File

@@ -0,0 +1,833 @@
<template>
<div class="ui container">
<div class="top-field">
<div class="title">启智社区国产算力英雄榜</div>
<div class="descr">本页面仅统计国产算力在启智AI协作平台的使用情况。数据更新时间:<span>{{ updateTime }}</span></div>
</div>
<div class="sort-field">
<div class="sort-conds">
<div class="sort-tab-c">
<div class="tab" :class="item.key == tabIndex ? 'active' : ''" v-for="(item) in tabList" :key="item.key"
@click="changeTab(item)">
{{ item.label }}
</div>
</div>
<div class="sort-type-c">
<el-select :size="useSmall ? 'small' : 'default'" v-model="sortType" @change="changeSort">
<el-option v-for="(item, index) in sortList" :key="item.key" :value="item.key"
:label="item.label"></el-option>
</el-select>
</div>
</div>
<div class="table-container" style="min-height:360px;">
<el-table class="table" :data="tableData" style="width:100%" v-loading="loading" row-key="id">
<el-table-column prop="rank" label="排名" align="center" header-align="center" width="80"></el-table-column>
<el-table-column prop="card_type" label="卡类型" align="left" header-align="left"></el-table-column>
<el-table-column prop="resource_type" label="计算资源" align="left" header-align="left">
</el-table-column>
<el-table-column prop="company" label="厂家" align="left" header-align="left"></el-table-column>
<el-table-column prop="access_time" label="接入平台时间" align="center" header-align="center"
min-width="110"></el-table-column>
<el-table-column prop="sortValue" align="left" header-align="center" min-width="360">
<template #header>
<div v-html="sortObj.theader"></div>
</template>
<template slot-scope="scope">
<div class="table-bar">
<div class="bar-c">
<div class="bar" :style="`width:${scope.row.barWith}%;${scope.row.barWith > 0 ? 'min-width:1px' : ''}`">
<template v-if="scope.$index == 0 && useShrink">
<div></div>
<div></div>
<div></div>
</template>
</div>
</div>
<div class="bar-value">{{ scope.row.countShow }}</div>
</div>
</template>
</el-table-column>
<template slot="empty">
<span style="font-size: 12px">{{
loading ? $t('loading') : $t('noData')
}}</span>
</template>
</el-table>
</div>
</div>
<div class="partners-field">
<div class="partners-title">启智社区国产算力合作伙伴</div>
<div class="partners-c">
<div class="img-c" v-for="(item, index) in partners" :key="index">
<img :src="item.icon" :alt="item.name">
</div>
</div>
</div>
<div class="apply-field">
<a :href="applyLink" class="apply-btn">加速卡申请加入启智AI协作平台请参考</a>
</div>
<div class="card-field">
<div class="card" v-for="(card, cardIndex) in cards" :key="cardIndex">
<div class="title-c">
<div class="title">{{ card.name }}</div>
<div class="icon-c">
<img :src="card.icon" alt="" />
</div>
</div>
<div class="descr-c" v-if="card.descr">
<p v-for="(descr, descrIndex) in card.descr" :key="descrIndex"> {{ descr }}</p>
</div>
<div class="feature-c" v-if="card.features">
<div class="feature" v-for="(feature, featureIndex) in card.features" :key="featureIndex">
<p class="title">{{ feature.title }}</p>
<p class="item" v-for="(item, itemIndex) in feature.list" :key="itemIndex"> {{ item }}</p>
</div>
</div>
<div class="table-c" v-if="card.table">
<table class="table" :class="card.table.tableClass">
<tr>
<td class="title" colspan="2">{{ card.table.title }}</td>
</tr>
<tr v-for="(row, rowIndex) in card.table.fields" :key="rowIndex">
<td class="field-title" v-html="row.title"></td>
<td v-html="row.value"></td>
</tr>
</table>
</div>
<div class="use-example-c" v-if="card.useExample">
<div class="title">{{ card.useExample.title }}</div>
<div v-for="(link, linkIndex) in card.useExample.list" :key="linkIndex">
<a :href="link"> {{ link }}</a>
</div>
</div>
</div>
<div class="card placeholder" v-if="cards.length % 2 == 1"></div>
</div>
</div>
</template>

<script>
import { getDomesticCardData } from '~/apis/modules/domestic';
import { formatDate } from 'element-ui/lib/utils/date-util';

const manufacturerIconMap = {
ascend: '/img/domestic/ascend.svg',
enflame: '/img/domestic/enflame.svg',
cambricon: '/img/domestic/cambricon.svg',
iluvatar: '/img/domestic/iluvatar.svg',
metax: '/img/domestic/metax.svg',
hygon: '/img/domestic/hygon.png'
};

export default {
data() {
return {
loading: false,
useSmall: false,
tabList: [
{ key: 'all', label: '总排名' },
{ key: '7', label: '近7天排名' },
{ key: '30', label: '近30天排名' },
],
tabIndex: 'all',
sortList: [
{ key: 'card', label: '使用时长', theader: '使用时长(卡时)<span>说明:卡时=云脑任务运行时长*卡数</span>', unit: '卡时' },
{ key: 'user', label: '使用用户数', theader: '使用用户数(人)', unit: '人' },
{ key: 'task', label: '使用次数(创建云脑任务数)', theader: '使用次数(个)', unit: '个' },
],
sortType: 'card',
tableData: [],
updateTime: '',
useShrink: false,
partners: [
{ name: '', icon: manufacturerIconMap.ascend },
{ name: '', icon: manufacturerIconMap.enflame },
{ name: '', icon: manufacturerIconMap.cambricon },
{ name: '', icon: manufacturerIconMap.iluvatar },
{ name: '', icon: manufacturerIconMap.metax },
{ name: '', icon: manufacturerIconMap.hygon },
],
applyLink: 'https://openi.pcl.ac.cn/OpenIOSSG/promote/src/branch/master/XPRZ.md',
cards: [{
name: '华为昇腾Ascend 910',
icon: manufacturerIconMap.ascend,
descr: [
'昇腾(HUAWEI Ascend) 910是业界算力最强的AI处理器,基于自研华为达芬奇架构3D Cube技术,实现业界最佳AI性能与能效,架构灵活伸缩,支持云边端全栈全场景应用。算力方面,昇腾910完全达到设计规格,半精度(FP16)算力达到320 TFLOPS,整数精度(INT8)算力达到640 TOPS,功耗310W。'
],
features: [
{ title: '产品特点', list: ['- 自研华为达芬奇架构NPU', '- 640 TOPS@INT8,320TFLOPS@FP16', '- 最大功耗310W'], },

],
table: {
title: '关键特性',
fields: [
{ title: 'Architecture', value: 'HUAWEI Da Vinci' },
{ title: 'Computing Engine', value: '3D Cube' },
{ title: 'Performance', value: '320 TFLOPS @FP16 and 640 TOPS @INT8' },
{ title: 'Max Power', value: '310W' },
{ title: 'Process', value: 'N7+' },
]
},
useExample: {
title: '在启智AI协作平台使用案例:',
list: [
'https://openi.pcl.ac.cn/OpenIOSSG/MNIST_Example'
]
},
}, /*{
name: '华为昇腾Ascend D910B',
icon: manufacturerIconMap.ascend,
descr: [
'昇腾(HUAWEI Ascend) 910是业界算力最强的AI处理器,基于自研华为达芬奇架构3D Cube技术,实现业界最佳AI性能与能效,架构灵活伸缩,支持云边端全栈全场景应用。算力方面,昇腾910完全达到设计规格,半精度(FP16)算力达到320 TFLOPS,整数精度(INT8)算力达到640 TOPS,功耗310W。'
],
table: {
title: '关键特性',
fields: [
{ title: 'Architecture', value: 'HUAWEI Da Vinci' },
{ title: 'Computing Engine', value: '3D Cube' },
{ title: 'Performance', value: '320 TFLOPS @FP16 and 640 TOPS @INT8' },
{ title: 'Max Power', value: '310W' },
{ title: 'Process', value: 'N7+' },
]
}
},*/ {
name: '燧原科技云燧ENFLAME-T20',
icon: manufacturerIconMap.enflame,
descr: [
'云燧T20是基于邃思2.0芯片打造的面向数据中心的第二代人工智能训练加速卡,具有模型覆盖面广、性能强、软件生态开放等特点,可支持多种人工智能训练场景。同时具备灵活的可扩展性,提供业界领先的人工智能算力集群方案。产品优势特点如下:'
],
features: [
{ title: '澎湃算力 高精训练', list: ['- 领先的TF32等浮点AI算力', '- 基于HBM2E的高吞吐低延时', '- 动态性特征支持'], },
{ title: '专属通道 算力扩展', list: ['- 独立的高带宽通道,加速卡间通信', '- 独家的机内4卡全互联方案', '- 增强的单机8卡互联方案'], },
{ title: '广泛支持 生态友好', list: ['- C++和Python开发接口', '- 主流框架支持,国产框架适配加速', '- 算子与模型广泛支持'], },
{ title: '工具开放 高效开发', list: ['- 多层次API接口开放', '- 完整工具链,支持高效开发与模型调试', '- 编程模型开放,支持第三方深度定制'], },
],
useExample: {
title: '在启智AI协作平台使用案例:',
list: [
'https://openi.pcl.ac.cn/Enflame/GCU_Pytorch1.10.0_Example',
'https://openi.pcl.ac.cn/Enflame/GCU_PaddlePaddle_Example'
]
},
}, {
name: '沐曦曦思N100',
icon: manufacturerIconMap.metax,
descr: [
'沐曦在2020年9月成立于上海,它致力于为异构计算提供安全可靠的通用GPU芯片及解决方案,可广泛应用于人工智能、智慧城市、数据中心、云计算、自动驾驶、数字孪生、元宇宙等前沿领域,为数字经济发展提供强大的算力支撑。',
'此次启智AI协作平台上线的沐曦GPGPU计算资源主要来自于沐曦的首款产品:“曦思N100” 人工智能推理GPU。曦思N100是一款面向云端数据中心应用的GPU人工智能加速卡,可广泛应用于智慧城市、智慧交通、机器视觉、智能视频处理等场景,该产品具备如下特点:'
],
features: [
{ title: '创新架构,多样算力', list: ['- 面向场景优化的异构GPGPU架构,兼顾计算效率和通用性', '- 单卡提供高达160TOPS INT8 算力和80TFLOPS FP16 算力'], },
{ title: '卓越的视频处理能力', list: ['- 多种视频格式兼容且支持8K分辨率', '- 超高密度视频编解码,在基于视频+AI的场景极具性价比'], },
{ title: '高带宽,低延时', list: ['- 集成HBM2E 高带宽内存', '- 率先支持PCIe5.0'], },
{ title: '成熟易用的软件栈', list: ['- 兼容ONNX、Opencv、FFmpeg等主流框架', '- 完善的Model Zoo和应用示例,开箱即用'], },
],
table: {
title: '曦思N100人工智能推理GPU产品规格',
fields: [
{ title: 'AI算力', value: '160TOPS INT8; 80TFLOPS FP16/BF16' },
{ title: '显存', value: '16GB HBM2E, 带宽460GB/s' },
{ title: '视频解码', value: '120x1080P30, H.264/H.265/AV1/AVS2, 支持8K分辨率' },
{ title: '视频编码', value: '120x1080P30, H.264/H.265/AV1, 支持8K分辨率' },
{ title: 'PCIe接口', value: 'PCIe5.0/4.0/3.0 x16' },
{ title: '虚拟化', value: '单卡可支持1/2/4个用户实例' },
{ title: '功耗', value: '最大70W' },
{ title: '散热设计', value: '被动散热' },
{ title: '板卡形态', value: '单槽半高半长(HHHL)' },
]
},
useExample: {
title: '在启智AI协作平台使用案例:',
list: [
'https://openi.pcl.ac.cn/Metax/Metax202309121140356/src/branch/master/classification',
'https://openi.pcl.ac.cn/Metax/Metax202309121140356/src/branch/master/detecion'
]
},
}, {
name: '寒武纪MLU290',
icon: manufacturerIconMap.cambricon,
descr: [
'MLU290-M5智能加速卡搭载寒武纪首颗训练芯片思元290,采用台积电7nm先进制程工艺,采用MLUv02扩展架构。MLU290-M5智能加速卡采用开放加速模块OAM设计,具备64个MLU Core,1.23TB/s内存带宽以及全新MLU-Link芯片间互联技术,全面支持AI训练、推理或混合型人工智能计算加速任务。',
],
table: {
title: '思元290-M5 产品规格',
fields: [
{ title: '产品名称', value: 'MLU290-M5' },
{ title: '核心架构', value: 'Cambricon MLUv02 Extended' },
{ title: '制程工艺', value: '7nm' },
{ title: '自适应精度训练算力', value: '512 TOPS(INT8)<br>256 TOPS(INT16)<br>64 TOPS(CINT32)' },
{ title: 'DirectCV<sup>TM</sup>视频解码', value: '128 Streams 全高清视频' },
{ title: 'DirectCV<sup>TM</sup>图片解码', value: '3200 Frames/s 全高清图片' },
{ title: '内存类型', value: 'HBM2高带宽内存' },
{ title: '内存容量', value: '32GB' },
{ title: '内存位宽', value: '4096 bit' },
{ title: '内存带宽', value: '1228 GB/s' },
{ title: '系统接口', value: 'x 16 PCIe 4.0' },
{ title: 'MLU-Link<sup>TM</sup>接口', value: '6 Ports, 48 Lanes, 50 Gbps' },
{ title: 'MLU-Link<sup>TM</sup>带宽', value: '聚合带宽600GB/s Bi-direction' },
{ title: '最大热功耗', value: '350W' },
{ title: '形态', value: 'OAM (54V)' },
{ title: '尺寸', value: '102mm x 165mm' },
{ title: '含散热器重量', value: '1470g' },
]
}
}, {
name: '天垓100(BI -V100)',
icon: manufacturerIconMap.iluvatar,
descr: [
'天数智芯天垓100加速卡是一款基于天垓100芯片的通用GPU训练加速卡。',
'天垓100芯片采用通用GPU架构,支持FP32,FP16,INT32/16/8等多精度数据混合训练,并可提供147 TFLOPS@FP16/BF16的峰值算;兼容多种主流服务器和市场主流生态,兼容CUDA生态,可助力客户实现无痛系统迁移;可提供灵活的编程能力,超强的性能及富有吸引力的性价比。同时,天垓100芯片可提供灵活的编程能力和完善高效的软件栈工具,支持x86和ARM等架构,能够支持国内外主流软硬件生态和各种深度学习框架、算法模型和加速库,应用迁移成本低、耗时短、无需重新开发,用户几乎可以无感知地使用天垓100产品。'
],
table: {
title: '天垓100产品规格',
fields: [
{ title: '算力性能', value: '37 TFLOPS@FP32<br>147 TFLOPS@FP16/BF16<br>295 TOPS@INT8<br>支持INT16、INT32计算' },
{ title: '板级功耗', value: '250W TDP' },
{ title: '内存理论数据', value: '32GB HBM2' },
{ title: '接口', value: 'PCIe Gen4.0 x16lane<br>共享64GB/s主控双向带宽,共享64GB/s片间互联带宽' },
{ title: '板卡规格', value: '全长全高双槽PCIe卡<br>被动散热' },
{ title: '虚拟化', value: '支持Hypervisor,Docker' },
]
},
useExample: {
title: '在启智AI协作平台使用案例:',
list: [
'https://openi.pcl.ac.cn/iluvatar/bert_crf_sequence_labeling',
'https://openi.pcl.ac.cn/iluvatar/resnet50',
'https://openi.pcl.ac.cn/iluvatar/paddleyolo',
]
},
}, {
name: '智铠100(MR-V100)',
icon: manufacturerIconMap.iluvatar,
descr: [
'天数智芯智铠100加速卡是一款基于智铠100芯片的通用GPU推理加速卡。',
'智铠100芯片采用通用GPU架构,支持FP32,FP16,INT8等多精度推理。智铠100具有应用覆盖广,计算性能高,应用成本低及落地支持强的特性,兼容CUDA生态,提供灵活的编程能力,超强的性能及富有吸引力的性价比。智铠100芯片可提供完善高效的软件栈工具,支持X86和ARM等架构。天数智芯软件栈集成了多种主流的深度学习编程框架,并且提供了基于C/C++的编程接口拓展和高性能函数库,提供了一系列调试和调优工具,为高性能计算和人工智能应用的开发和部署提供了便利。'
],
table: {
title: '智铠100产品规格',
fields: [
{ title: '峰值算力', value: '24 TFLOPS @ FP32<br>96 TFLOPS @ FP16<br>384 TOPS @ INT8' },
{ title: '内存', value: '32GB HBM2E' },
{ title: '视频图像处理', value: '128路FHD解码<br>HEVC/AVC/P9/AVS2<br>2000/500 FPS JPEG编解码' },
{ title: '主控及互联', value: 'PCIe 4.0x16,64GB/s双向宽带' },
{ title: '热设计功耗', value: '150W' },
{ title: '板卡规格', value: '全高全长,PCIe单槽' },
]
},
useExample: {
title: '在启智AI协作平台使用案例:',
list: [
'https://openi.pcl.ac.cn/iluvatar/bert_crf_sequence_labeling',
'https://openi.pcl.ac.cn/iluvatar/resnet50',
'https://openi.pcl.ac.cn/iluvatar/paddleyolo',
]
},
}, {
name: '海光DCU',
icon: manufacturerIconMap.hygon,
descr: [
'DCU深算处理器是由海光信息技术有限公司开发的一款高性能通用异构处理器。',
'DCU深度计算处理器(DCU Z100)基于通用图形处理器理念设计,更加适合为人工智能计算提供强大的算力。DCU Z100拥有64组计算单元,共计8192个计算核心,超高速32GB HBM2内存和高达1TB/s的内存带宽,可以完美支持深度学习训练场景,轻松应对复杂神经网络训练。',
'DCU Z100拥有10.8T的双精度浮点运算能力,是高性能计算业务的不二之选。优异的架构设计和超高计算能力,可为生命科学、能源勘探、工业设计、航空航天、分子动力学计算等行业提供更高性价比的计算方案。',
],
table: {
title: 'DCU Z100规格参数',
fields: [
{ title: 'Category', value: 'Z100' },
{ title: 'Architecture', value: 'Zifang' },
{ title: 'Process (nm)', value: '7' },
{ title: 'Streaming Multiprocessors(SMs/CUs)', value: '64' },
{ title: 'FP32 Units / SM (CU)', value: '64' },
{ title: 'FP32 Units (Vector)', value: '4096' },
{ title: 'FP64 Units (Vector)', value: '4096' },
{ title: 'Tensor Core/Matrix Units', value: '-' },
{ title: 'Threads / Warp', value: '64' },
{ title: 'Max Warps / SM (CU)', value: '40' },
{ title: 'Max Threads / SM (CU)', value: '2560' },
{ title: 'Sparse Matrix', value: 'No' },
{ title: 'Peak FP64 Perf. (TFLOPs)', value: '10.8' },
{ title: 'Peak FP32 Perf. (TFLOPs)', value: '14.7' },
{ title: 'Peak FP16 Perf. (TFLOPs)', value: '29.5' },
{ title: 'Boost Core Clock Speed (MHz)', value: '1319' },
{ title: 'HBM2/HBM2E Memory (GB)', value: '16/32' },
{ title: 'DIE Size (mm<sup>2</sup>)', value: '356' },
{ title: 'TDP (W)', value: '350' },
],
tableClass: 'average',
}
}]
};
},
components: {},
computed: {
sortObj() {
return this.sortList.filter(itm => itm.key == this.sortType)[0] || {};
}
},
methods: {
changeTab(tab) {
if (tab.key == this.tabIndex) return;
this.tabIndex = tab.key;
this.getData();
},
changeSort() {
this.getData();
},
transformNumber(value, unit) {
const param = {};
const k = 10000;
const sizes = ['', '万', '亿', '万亿'];
let i;
if (value < k) {
param.value = value;
param.unit = '';
} else {
i = Math.floor(Math.log(value) / Math.log(k));
param.value = ((value / Math.pow(k, i))).toFixed(2);
param.unit = sizes[i];
}
return param.value + ' ' + param.unit + unit;
},
getData() {
this.loading = true;
getDomesticCardData({
type: this.tabIndex,
category: this.sortType
}).then(res => {
this.loading = false;
res = res.data;
if (res.code == 0) {
const data = (res.data || []).map((itm, index) => ({
...itm,
rank: index + 1,
}));
if (data.length) {
const first = data[0].count;
const second = data[1].count;
this.useShrink = first && second && first / second >= 10;
data.map((item, index) => {
item.id = Math.random();
if (index == 0) {
item.barWith = 100;
} else {
if (this.useShrink) {
item.barWith = second == 0 ? 0 : parseFloat((80 * (item.count / second)).toFixed(2));
} else {
item.barWith = first == 0 ? 0 : parseFloat((100 * (item.count / first)).toFixed(2));
}
}
if (first == 0) {
item.barWith = 0;
}
item.countShow = this.transformNumber(item.count, this.sortObj.unit);
})
this.updateTime = formatDate(new Date(data[0].updated_unix * 1000), 'yyyy-MM-dd HH:mm:ss');
} else { }
this.tableData = data;
} else {
console.log(res);
}
}).catch(err => {
this.loading = false;
console.log(err);
})
},
},
created() {
this.getData();
},
mounted() {
if (document.body.clientWidth <= 767) {
this.useSmall = true;
}
},
beforeDestroy() { },
};
</script>

<style scoped lang="less">
.top-field {
text-align: center;
padding-top: 42px;
margin-bottom: 20px;

.title {
color: rgba(16, 16, 16, 1);
font-size: 28px;
margin-bottom: 24px;
}

.descr {
color: rgba(136, 136, 136, 0.87);
font-size: 14px;
}
}

.sort-field {
margin-bottom: 20px;

.sort-conds {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;

.sort-tab-c {
display: flex;
margin-bottom: 16px;
margin-right: 20px;

.tab {
width: 110px;
height: 40px;
border-color: rgba(0, 0, 0, 0.1);
border-width: 1px;
border-style: solid;
color: rgba(16, 16, 16, 1);
display: flex;
align-items: center;
justify-content: center;
border-left: none;
cursor: pointer;

&:first-child {
border-radius: 4px 0px 0px 4px;
border-left: 1px solid rgba(0, 0, 0, 0.1);
}

&:last-child {
border-radius: 0px 4px 4px 0px;
}

&.active {
color: rgba(91, 185, 115, 1);
border-color: rgba(33, 186, 69, 1);
border-left: 1px solid rgba(33, 186, 69, 1);
}
}

}

.sort-type-c {
margin-bottom: 16px;
}
}

.table-container {
.table {
/deep/ .el-table__header {
th {
background: #f1f8ff;
color: rgba(16, 16, 16, 1);
font-size: 14px;

span {
font-weight: normal;
}
}
}

/deep/ .el-table__body {
td {
font-size: 14px;
}
}
}

.table-bar {
width: 100%;
display: flex;
display: flex;
align-items: center;
min-width: 200px;

.bar-c {
flex: 1;
display: flex;
align-items: center;
justify-content: flex-end;


.bar {
overflow: hidden;
height: 8px;
background: url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20version%3D%221.1%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%221%22%20x1%3D%220%22%20x2%3D%221%22%20y1%3D%220%22%20y2%3D%220%22%20gradientTransform%3D%22matrix(-0.9910000000000001%2C%20-0.014999999999999873%2C%200.000003944485025566073%2C%20-0.9910000000000001%2C%200.999%2C%200.125)%22%3E%3Cstop%20stop-color%3D%22%233291f8%22%20stop-opacity%3D%221%22%20offset%3D%220%22%3E%3C%2Fstop%3E%3Cstop%20stop-color%3D%22%23c9bcea%22%20stop-opacity%3D%221%22%20offset%3D%221%22%3E%3C%2Fstop%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Crect%20width%3D%22100%25%22%20height%3D%22100%25%22%20fill%3D%22url(%231)%22%3E%3C%2Frect%3E%3C%2Fsvg%3E");

div {
float: right;
height: 100%;
background-color: white;
width: 8px;
margin-right: 8px;
border-top: 1px solid #cce4fd;
border-bottom: 1px solid #cce4fd;
box-sizing: border-box;
}
}
}

.bar-value {
width: 100px;
margin-left: 16px;
}
}
}
}

.partners-field {
margin-top: 42px;
text-align: center;

.partners-title {
color: rgba(16, 16, 16, 1);
font-size: 18px;
margin-bottom: 10px;
}

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

.img-c {
width: 200px;
height: 80px;
margin: 10px 20px;
display: flex;
align-items: center;
justify-content: center;
padding: 16px;

img {
max-height: 100%;
max-width: 100%;
}
}
}
}

.apply-field {
margin-top: 12px;
text-align: center;
display: flex;
align-items: center;
justify-content: center;

.apply-btn {
height: 40px;
border-radius: 5px;
background: linear-gradient(30deg, rgba(59, 182, 254, 1) 13.4%, rgba(142, 76, 183, 1) 85.87%);
color: rgba(255, 255, 255, 1);
font-size: 14px;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
padding: 0 20px;
}
}

.card-field {
display: flex;
flex-wrap: wrap;
justify-content: center;
margin-top: 16px;

.card {
width: 45%;
min-width: 300px;
max-width: 650px;
border-radius: 10px;
border-color: rgba(201, 188, 234, 0.4);
border-width: 1px;
border-style: solid;
box-shadow: rgba(157, 197, 226, 0.2) 0px 5px 10px 0px;
margin: 20px;
padding: 28px;
background: url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20version%3D%221.1%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%221%22%20x1%3D%220%22%20x2%3D%221%22%20y1%3D%220%22%20y2%3D%220%22%20gradientTransform%3D%22matrix(-0.41100000000000014%2C%201.129%2C%20-0.9330578512396693%2C%20-0.41100000000000014%2C%200.911%2C%20-0.129)%22%3E%3Cstop%20stop-color%3D%22%23f1ebff%22%20stop-opacity%3D%221%22%20offset%3D%220.005%22%3E%3C%2Fstop%3E%3Cstop%20stop-color%3D%22%23eef2ff%22%20stop-opacity%3D%221%22%20offset%3D%220.19%22%3E%3C%2Fstop%3E%3Cstop%20stop-color%3D%22%23ffffff%22%20stop-opacity%3D%221%22%20offset%3D%220.59%22%3E%3C%2Fstop%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Crect%20width%3D%22100%25%22%20height%3D%22100%25%22%20fill%3D%22url(%231)%22%3E%3C%2Frect%3E%3C%2Fsvg%3E");

.title-c {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 10px;

.title {
font-weight: 700;
font-size: 16px;
color: #101010;
}

.icon-c {
min-width: 120px;
height: 32px;
display: flex;
align-items: center;
justify-content: flex-end;

img {
max-height: 100%;
}
}
}

.descr-c {
line-height: 24px;
color: rgba(16, 16, 16, 1);
font-size: 14px;

p {
margin-bottom: 8px;
line-height: 24px;
}
}

.feature-c {
font-size: 14px;

.feature {
margin-bottom: 8px;

p {
margin-bottom: 8px;
}

.title {
font-weight: bold;
margin-bottom: 6px;
}
}
}

.table-c {
display: flex;
align-items: center;
justify-content: center;

.table {
width: 85%;

.title {
font-weight: bold;
}

.field-title {
text-align: right;
}

th,
td {
border: 1px solid #EBEEF5;
padding: 6px 8px;
font-size: 14px;

sup {
font-size: 12px;
}
}

&.average {

th,
td {
width: 50%;
}
}
}
}

.use-example-c {
margin-top: 12px;

.title {
font-weight: bold;
margin-bottom: 8px;
}

a {
margin-bottom: 6px;
line-height: 1.4285em;
color: rgb(22, 132, 252);
word-wrap: break-word;
}
}

&.placeholder {
box-shadow: none;
background: none;
border: none;
}
}
}

@media only screen and (max-width: 767px) {
.sort-field {
.sort-conds {
margin-bottom: 8px;

.sort-tab-c {
margin-bottom: 8px;

.tab {
height: 32px;
font-size: 12px;
}
}

.sort-type-c {
margin-bottom: 8px;
}
}
}

.partners-field {

.partners-c {

.img-c {
width: 150px;
height: 60px;
margin: 10px 10px;
padding: 12px;
}
}
}

.card-field {
margin-top: 16px;

.card {
width: 100%;
margin: 20px 0;
padding: 20px;

.title-c {

.icon-c {
min-width: 80px;
height: 20px;
display: flex;
align-items: center;
justify-content: flex-end;
}
}

.table-c {
display: flex;
align-items: center;
justify-content: center;

.table {
width: 100%;
}
}

&.placeholder {
display: none;
}
}
}
}
</style>

+ 17
- 0
web_src/vuepages/pages/explore/domestic/vp-explore-domestic.js View File

@@ -0,0 +1,17 @@
import Vue from 'vue';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import localeEn from 'element-ui/lib/locale/lang/en';
import localeZh from 'element-ui/lib/locale/lang/zh-CN';
import { i18n, lang } from '~/langs';
import App from './index.vue';

Vue.use(ElementUI, {
locale: lang === 'zh-CN' ? localeZh : localeEn,
size: 'small',
});

new Vue({
i18n,
render: (h) => h(App),
}).$mount('#__vue-root');

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

@@ -46,7 +46,7 @@
<ModelSelect ref="modelRef" v-if="formCfg.model" v-model="state.model" :required="formCfg.model.required"
:multiple="formCfg.model.multiple" :repoOwnerName="repoOwnerName" :repoName="repoName"></ModelSelect>
<ImageSelectV2 ref="imagev2Ref" v-if="formCfg.imagev2" v-model="state.image" :images="imageList"
:required="formCfg.imagev2.required">
:configs="pageCfg" :spec="state.spec" :networkType="state.networkType" :required="formCfg.imagev2.required">
</ImageSelectV2>
<DatasetSelect ref="datasetRef" v-if="formCfg.dataset" v-model="state.dataset"
:required="formCfg.dataset.required" :type="formCfg.dataset.type != undefined ? formCfg.dataset.type : -1"


Loading…
Cancel
Save