Browse Source

Merge remote-tracking branch 'origin/V20220415' into fix-1639

# Conflicts:
#	templates/repo/editor/upload.tmpl
tags/v1.22.4.1^2
chenyifan01 3 years ago
parent
commit
ec78b22b84
74 changed files with 8497 additions and 801 deletions
  1. +0
    -70
      custom/public/css/git.openi.css
  2. +1
    -0
      models/action.go
  3. +1
    -0
      models/attachment.go
  4. +58
    -2
      models/cloudbrain.go
  5. +39
    -27
      models/dataset.go
  6. +199
    -0
      models/dbsql/dataset_foreigntable_for_es.sql
  7. +227
    -0
      models/dbsql/issue_foreigntable_for_es.sql
  8. +545
    -0
      models/dbsql/repo_foreigntable_for_es.sql
  9. +317
    -0
      models/dbsql/user_foreigntable_for_es.sql
  10. +0
    -5
      models/file_chunk.go
  11. +4
    -0
      models/models.go
  12. +99
    -0
      models/org.go
  13. +10
    -7
      models/repo.go
  14. +7
    -3
      models/repo_list.go
  15. +10
    -0
      models/repo_statistic.go
  16. +83
    -0
      models/search_record.go
  17. +6
    -0
      models/user.go
  18. +394
    -172
      models/user_business_analysis.go
  19. +86
    -0
      models/user_business_struct.go
  20. +3
    -0
      modules/auth/cloudbrain.go
  21. +49
    -14
      modules/cloudbrain/cloudbrain.go
  22. +12
    -0
      modules/cron/tasks_basic.go
  23. +1
    -1
      modules/modelarts/modelarts.go
  24. +16
    -11
      modules/setting/setting.go
  25. +34
    -3
      options/locale/locale_en-US.ini
  26. +32
    -2
      options/locale/locale_zh-CN.ini
  27. +9
    -5
      public/home/home.js
  28. +1305
    -0
      public/home/search.js
  29. +3
    -3
      public/self/dataset_preview.js
  30. +3
    -3
      routers/admin/cloudbrains.go
  31. +12
    -2
      routers/api/v1/api.go
  32. +61
    -15
      routers/api/v1/repo/cloudbrain.go
  33. +57
    -24
      routers/api/v1/repo/modelarts.go
  34. +47
    -13
      routers/home.go
  35. +2
    -0
      routers/init.go
  36. +4
    -0
      routers/private/internal.go
  37. +4
    -0
      routers/private/tool.go
  38. +404
    -54
      routers/repo/cloudbrain.go
  39. +135
    -42
      routers/repo/modelarts.go
  40. +49
    -5
      routers/repo/user_data_analysis.go
  41. +14
    -10
      routers/repo/view.go
  42. +16
    -0
      routers/routes/routes.go
  43. +1194
    -0
      routers/search.go
  44. +1
    -1
      services/socketwrap/clientManager.go
  45. +3
    -3
      templates/admin/cloudbrain/list.tmpl
  46. +4
    -4
      templates/base/head_navbar.tmpl
  47. +4
    -4
      templates/base/head_navbar_fluid.tmpl
  48. +4
    -4
      templates/base/head_navbar_pro.tmpl
  49. +6
    -2
      templates/custom/select_dataset.tmpl
  50. +134
    -0
      templates/custom/select_dataset_train.tmpl
  51. +11
    -5
      templates/explore/datasets.tmpl
  52. +237
    -54
      templates/explore/organizations.tmpl
  53. +13
    -1
      templates/explore/repos.tmpl
  54. +95
    -0
      templates/explore/search_new.tmpl
  55. +13
    -1
      templates/repo/cloudbrain/benchmark/index.tmpl
  56. +21
    -8
      templates/repo/cloudbrain/benchmark/show.tmpl
  57. +491
    -90
      templates/repo/cloudbrain/show.tmpl
  58. +443
    -0
      templates/repo/cloudbrain/trainjob/new.tmpl
  59. +653
    -0
      templates/repo/cloudbrain/trainjob/show.tmpl
  60. +6
    -6
      templates/repo/datasets/index.tmpl
  61. +14
    -1
      templates/repo/debugjob/index.tmpl
  62. +14
    -1
      templates/repo/modelarts/inferencejob/index.tmpl
  63. +3
    -17
      templates/repo/modelarts/inferencejob/new.tmpl
  64. +7
    -1
      templates/repo/modelarts/inferencejob/show.tmpl
  65. +0
    -14
      templates/repo/modelarts/notebook/new.tmpl
  66. +430
    -56
      templates/repo/modelarts/notebook/show.tmpl
  67. +53
    -5
      templates/repo/modelarts/trainjob/index.tmpl
  68. +24
    -17
      templates/repo/modelarts/trainjob/new.tmpl
  69. +12
    -2
      templates/repo/modelarts/trainjob/show.tmpl
  70. +2
    -2
      templates/repo/view_file.tmpl
  71. +5
    -1
      templates/user/dashboard/feeds.tmpl
  72. +7
    -7
      web_src/js/components/ProAnalysis.vue
  73. +43
    -1
      web_src/js/components/UserAnalysis.vue
  74. +192
    -0
      web_src/less/openi.less

+ 0
- 70
custom/public/css/git.openi.css View File

@@ -44,12 +44,6 @@
-webkit-line-clamp: 2; -webkit-line-clamp: 2;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
} }
.ui.label{
font-weight: normal;
}
.active {
color: #0366D6 !important;
}


.opacity5{ opacity:0.5;} .opacity5{ opacity:0.5;}
.radius15{ border-radius:1.5rem !important; } .radius15{ border-radius:1.5rem !important; }
@@ -287,70 +281,6 @@
position: relative; position: relative;
} }


/**seach**/
/**搜索导航条适配窄屏**/
.seachnav{
overflow-x: auto;
overflow-y: hidden;
scrollbar-width: none; /* firefox */
-ms-overflow-style: none; /* IE 10+ */
}
.seachnav::-webkit-scrollbar {
display: none; /* Chrome Safari */
}
.ui.green.button, .ui.green.buttons .button{
background-color: #5BB973;
}
.seach .repos--seach{
padding-bottom: 0;
border-bottom: none;
}
.seach .ui.secondary.pointing.menu{
border-bottom: none;
}
.seach .ui.secondary.pointing.menu .item > i{
margin-right: 5px;
}
.seach .ui.secondary.pointing.menu .active.item{
border-bottom-width: 2px;
margin: 0 0 -1px;
}
.seach .ui.menu .active.item>.label {
background: #1684FC;
color: #FFF;
}
.seach .ui.menu .item>.label:not(.active.item>.label) {
background: #e8e8e8;
color: rgba(0,0,0,.6);
}

.highlight{
color: red;
}
.ui.list .list>.item>img.image+.content, .ui.list>.item>img.image+.content {
width: calc(100% - 3.0em);
margin-left: 0;
}

.seach .ui.list .list>.item .header, .seach .ui.list>.item .header{
margin-bottom: 0.5em;
font-size: 1.4rem !important;
font-weight: normal;
}
.seach .time, .seach .time a{
font-size: 12px;
color: grey;
}

.seach .list .item.members .ui.avatar.image {
width: 3.2em;
height: 3.2em;
}
.ui.list .list>.item.members>img.image+.content, .ui.list>.item.members>img.image+.content {
width: calc(100% - 4.0em);
margin-left: 0;
}

@media only screen and (max-width: 767px) { @media only screen and (max-width: 767px) {
.am-mt-30{ margin-top: 1.5rem !important;} .am-mt-30{ margin-top: 1.5rem !important;}
.ui.secondary.hometop.segment{ .ui.secondary.hometop.segment{


+ 1
- 0
models/action.go View File

@@ -57,6 +57,7 @@ const (
ActionCreateInferenceTask // 28 ActionCreateInferenceTask // 28
ActionCreateBenchMarkTask //29 ActionCreateBenchMarkTask //29
ActionCreateNewModelTask //30 ActionCreateNewModelTask //30
ActionCreateGPUTrainTask //31
) )


// Action represents user operation type and other information to // Action represents user operation type and other information to


+ 1
- 0
models/attachment.go View File

@@ -51,6 +51,7 @@ type Attachment struct {
FileChunk *FileChunk `xorm:"-"` FileChunk *FileChunk `xorm:"-"`
CanDel bool `xorm:"-"` CanDel bool `xorm:"-"`
Uploader *User `xorm:"-"` Uploader *User `xorm:"-"`
Md5 string `xorm:"-"`
} }


type AttachmentUsername struct { type AttachmentUsername struct {


+ 58
- 2
models/cloudbrain.go View File

@@ -20,9 +20,17 @@ type CloudbrainStatus string
type JobType string type JobType string
type ModelArtsJobStatus string type ModelArtsJobStatus string


const (
TypeCloudBrainOne int = iota
TypeCloudBrainTwo

TypeCloudBrainAll = -1
)

const ( const (
NPUResource = "NPU" NPUResource = "NPU"
GPUResource = "CPU/GPU" GPUResource = "CPU/GPU"
AllResource = "all"


//notebook storage category //notebook storage category
EVSCategory = "EVS" EVSCategory = "EVS"
@@ -87,6 +95,8 @@ const (
ModelArtsTrainJobCheckRunning ModelArtsJobStatus = "CHECK_RUNNING" //审核作业正在运行中 ModelArtsTrainJobCheckRunning ModelArtsJobStatus = "CHECK_RUNNING" //审核作业正在运行中
ModelArtsTrainJobCheckRunningCompleted ModelArtsJobStatus = "CHECK_RUNNING_COMPLETED" //审核作业已经完成 ModelArtsTrainJobCheckRunningCompleted ModelArtsJobStatus = "CHECK_RUNNING_COMPLETED" //审核作业已经完成
ModelArtsTrainJobCheckFailed ModelArtsJobStatus = "CHECK_FAILED" //审核作业失败 ModelArtsTrainJobCheckFailed ModelArtsJobStatus = "CHECK_FAILED" //审核作业失败

DURATION_STR_ZERO = "00:00:00"
) )


type Cloudbrain struct { type Cloudbrain struct {
@@ -160,7 +170,9 @@ func (task *Cloudbrain) ComputeAndSetDuration() {
if task.StartTime == 0 { if task.StartTime == 0 {
d = 0 d = 0
} else if task.EndTime == 0 { } else if task.EndTime == 0 {
d = time.Now().Unix() - task.StartTime.AsTime().Unix()
if !task.IsTerminal() {
d = time.Now().Unix() - task.StartTime.AsTime().Unix()
}
} else { } else {
d = task.EndTime.AsTime().Unix() - task.StartTime.AsTime().Unix() d = task.EndTime.AsTime().Unix() - task.StartTime.AsTime().Unix()
} }
@@ -172,9 +184,14 @@ func (task *Cloudbrain) ComputeAndSetDuration() {
task.TrainJobDuration = ConvertDurationToStr(d) task.TrainJobDuration = ConvertDurationToStr(d)
} }


func (task *Cloudbrain) IsTerminal() bool {
status := task.Status
return status == string(ModelArtsTrainJobCompleted) || status == string(ModelArtsTrainJobFailed) || status == string(ModelArtsTrainJobKilled) || status == string(ModelArtsStopped) || status == string(JobStopped) || status == string(JobFailed) || status == string(JobSucceeded)
}

func ConvertDurationToStr(duration int64) string { func ConvertDurationToStr(duration int64) string {
if duration == 0 { if duration == 0 {
return "00:00:00"
return DURATION_STR_ZERO
} }
return util.AddZero(duration/3600) + ":" + util.AddZero(duration%3600/60) + ":" + util.AddZero(duration%60) return util.AddZero(duration/3600) + ":" + util.AddZero(duration%3600/60) + ":" + util.AddZero(duration%60)
} }
@@ -191,6 +208,19 @@ func IsCloudBrainOneDebugJobTerminal(status string) bool {
return status == string(JobStopped) || status == string(JobFailed) || status == string(JobSucceeded) return status == string(JobStopped) || status == string(JobFailed) || status == string(JobSucceeded)
} }


func ParseAndSetDurationFromCloudBrainOne(result JobResultPayload, task *Cloudbrain) {
isActivated := result.JobStatus.CreatedTime > 0
if task.StartTime == 0 && isActivated {
task.StartTime = timeutil.TimeStamp(result.JobStatus.CreatedTime / 1000)
}
if task.EndTime == 0 && IsCloudBrainOneDebugJobTerminal(task.Status) && isActivated {
if result.JobStatus.CompletedTime > 0 {
task.EndTime = timeutil.TimeStamp(result.JobStatus.CompletedTime / 1000)
}
}
task.ComputeAndSetDuration()
}

type CloudbrainInfo struct { type CloudbrainInfo struct {
Cloudbrain `xorm:"extends"` Cloudbrain `xorm:"extends"`
User `xorm:"extends"` User `xorm:"extends"`
@@ -1323,6 +1353,7 @@ func CloudbrainsVersionList(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int, e
} }


func CreateCloudbrain(cloudbrain *Cloudbrain) (err error) { func CreateCloudbrain(cloudbrain *Cloudbrain) (err error) {
cloudbrain.TrainJobDuration = DURATION_STR_ZERO
if _, err = x.Insert(cloudbrain); err != nil { if _, err = x.Insert(cloudbrain); err != nil {
return err return err
} }
@@ -1339,6 +1370,16 @@ func getRepoCloudBrain(cb *Cloudbrain) (*Cloudbrain, error) {
return cb, nil return cb, nil
} }


func getRepoCloudBrainWithDeleted(cb *Cloudbrain) (*Cloudbrain, error) {
has, err := x.Unscoped().Get(cb)
if err != nil {
return nil, err
} else if !has {
return nil, ErrJobNotExist{}
}
return cb, nil
}

func GetRepoCloudBrainByJobID(repoID int64, jobID string) (*Cloudbrain, error) { func GetRepoCloudBrainByJobID(repoID int64, jobID string) (*Cloudbrain, error) {
cb := &Cloudbrain{JobID: jobID, RepoID: repoID} cb := &Cloudbrain{JobID: jobID, RepoID: repoID}
return getRepoCloudBrain(cb) return getRepoCloudBrain(cb)
@@ -1355,6 +1396,12 @@ func GetCloudbrainByID(id string) (*Cloudbrain, error) {
return getRepoCloudBrain(cb) return getRepoCloudBrain(cb)
} }


func GetCloudbrainByIDWithDeleted(id string) (*Cloudbrain, error) {
idInt64, _ := strconv.ParseInt(id, 10, 64)
cb := &Cloudbrain{ID: idInt64}
return getRepoCloudBrainWithDeleted(cb)
}

func GetCloudbrainByJobIDAndVersionName(jobID string, versionName string) (*Cloudbrain, error) { func GetCloudbrainByJobIDAndVersionName(jobID string, versionName string) (*Cloudbrain, error) {
cb := &Cloudbrain{JobID: jobID, VersionName: versionName} cb := &Cloudbrain{JobID: jobID, VersionName: versionName}
return getRepoCloudBrain(cb) return getRepoCloudBrain(cb)
@@ -1467,6 +1514,15 @@ func GetCloudBrainUnStoppedJob() ([]*Cloudbrain, error) {
Find(&cloudbrains) Find(&cloudbrains)
} }


func GetStoppedJobWithNoDurationJob() ([]*Cloudbrain, error) {
cloudbrains := make([]*Cloudbrain, 0)
return cloudbrains, x.
In("status", ModelArtsTrainJobCompleted, ModelArtsTrainJobFailed, ModelArtsTrainJobKilled, ModelArtsStopped, JobStopped, JobFailed, JobSucceeded).
Where("train_job_duration is null or train_job_duration = '' ").
Limit(100).
Find(&cloudbrains)
}

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


+ 39
- 27
models/dataset.go View File

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


import ( import (
"code.gitea.io/gitea/modules/log"
"errors" "errors"
"fmt" "fmt"
"sort" "sort"
@@ -62,19 +63,20 @@ func (datasets DatasetList) loadAttributes(e Engine) error {
} }


set := make(map[int64]struct{}) set := make(map[int64]struct{})
userIdSet := make(map[int64]struct{})
datasetIDs := make([]int64, len(datasets)) datasetIDs := make([]int64, len(datasets))
for i := range datasets { for i := range datasets {
set[datasets[i].UserID] = struct{}{}
userIdSet[datasets[i].UserID] = struct{}{}
set[datasets[i].RepoID] = struct{}{} set[datasets[i].RepoID] = struct{}{}
datasetIDs[i] = datasets[i].ID datasetIDs[i] = datasets[i].ID
} }


// Load owners. // Load owners.
users := make(map[int64]*User, len(set))
users := make(map[int64]*User, len(userIdSet))
repos := make(map[int64]*Repository, len(set)) repos := make(map[int64]*Repository, len(set))
if err := e. if err := e.
Where("id > 0"). Where("id > 0").
In("id", keysInt64(set)).
In("id", keysInt64(userIdSet)).
Find(&users); err != nil { Find(&users); err != nil {
return fmt.Errorf("find users: %v", err) return fmt.Errorf("find users: %v", err)
} }
@@ -139,20 +141,7 @@ func SearchDatasetCondition(opts *SearchDatasetOptions) builder.Cond {
var cond = builder.NewCond() var cond = builder.NewCond()
cond = cond.And(builder.Neq{"dataset.status": DatasetStatusDeleted}) cond = cond.And(builder.Neq{"dataset.status": DatasetStatusDeleted})


if len(opts.Keyword) > 0 {
cond = cond.And(builder.Or(builder.Like{"dataset.title", opts.Keyword}, builder.Like{"dataset.description", opts.Keyword}))
}

if len(opts.Category) > 0 {
cond = cond.And(builder.Eq{"dataset.category": opts.Category})
}

if len(opts.Task) > 0 {
cond = cond.And(builder.Eq{"dataset.task": opts.Task})
}
if len(opts.License) > 0 {
cond = cond.And(builder.Eq{"dataset.license": opts.License})
}
cond = generateFilterCond(opts, cond)


if opts.RepoID > 0 { if opts.RepoID > 0 {
cond = cond.And(builder.Eq{"dataset.repo_id": opts.RepoID}) cond = cond.And(builder.Eq{"dataset.repo_id": opts.RepoID})
@@ -162,14 +151,12 @@ func SearchDatasetCondition(opts *SearchDatasetOptions) builder.Cond {
cond = cond.And(builder.Eq{"dataset.status": DatasetStatusPublic}) cond = cond.And(builder.Eq{"dataset.status": DatasetStatusPublic})
cond = cond.And(builder.Eq{"attachment.is_private": false}) cond = cond.And(builder.Eq{"attachment.is_private": false})
if opts.OwnerID > 0 { if opts.OwnerID > 0 {
if len(opts.Keyword) == 0 {
cond = cond.Or(builder.Eq{"repository.owner_id": opts.OwnerID})
} else {
subCon := builder.NewCond()
subCon = subCon.And(builder.Eq{"repository.owner_id": opts.OwnerID}, builder.Or(builder.Like{"dataset.title", opts.Keyword}, builder.Like{"dataset.description", opts.Keyword}))
cond = cond.Or(subCon)

}

subCon := builder.NewCond()
subCon = subCon.And(builder.Eq{"repository.owner_id": opts.OwnerID})
subCon = generateFilterCond(opts, subCon)
cond = cond.Or(subCon)

} }
} else if opts.OwnerID > 0 { } else if opts.OwnerID > 0 {
cond = cond.And(builder.Eq{"repository.owner_id": opts.OwnerID}) cond = cond.And(builder.Eq{"repository.owner_id": opts.OwnerID})
@@ -182,6 +169,25 @@ func SearchDatasetCondition(opts *SearchDatasetOptions) builder.Cond {
return cond return cond
} }


func generateFilterCond(opts *SearchDatasetOptions, cond builder.Cond) builder.Cond {
if len(opts.Keyword) > 0 {
cond = cond.And(builder.Or(builder.Like{"dataset.title", opts.Keyword}, builder.Like{"dataset.description", opts.Keyword}))
}

if len(opts.Category) > 0 {
cond = cond.And(builder.Eq{"dataset.category": opts.Category})
}

if len(opts.Task) > 0 {
cond = cond.And(builder.Eq{"dataset.task": opts.Task})
}
if len(opts.License) > 0 {
cond = cond.And(builder.Eq{"dataset.license": opts.License})
}

return cond
}

func SearchDatasetByCondition(opts *SearchDatasetOptions, cond builder.Cond) (DatasetList, int64, error) { func SearchDatasetByCondition(opts *SearchDatasetOptions, cond builder.Cond) (DatasetList, int64, error) {
if opts.Page <= 0 { if opts.Page <= 0 {
opts.Page = 1 opts.Page = 1
@@ -292,7 +298,13 @@ func getDatasetAttachments(e Engine, typeCloudBrain int, isSigned bool, user *Us
if err != nil { if err != nil {
return err return err
} }
attachment.FileChunk = fileChunks[0]
if len(fileChunks) > 0 {
attachment.Md5 = fileChunks[0].Md5
} else {
log.Error("has attachment record, but has no file_chunk record")
attachment.Md5 = "no_record"
}

attachment.CanDel = CanDelAttachment(isSigned, user, attachment) attachment.CanDel = CanDelAttachment(isSigned, user, attachment)
sortedRels.Rel[currentIndex].Attachments = append(sortedRels.Rel[currentIndex].Attachments, attachment) sortedRels.Rel[currentIndex].Attachments = append(sortedRels.Rel[currentIndex].Attachments, attachment)
} }
@@ -348,7 +360,7 @@ func GetDatasetByRepo(repo *Repository) (*Dataset, error) {
if has { if has {
return dataset, nil return dataset, nil
} else { } else {
return nil, errors.New("Not Found")
return nil, ErrNotExist{repo.ID}
} }
} }




+ 199
- 0
models/dbsql/dataset_foreigntable_for_es.sql View File

@@ -0,0 +1,199 @@
DELETE FROM public.dataset_es;
DROP FOREIGN TABLE public.dataset_es;
DROP TRIGGER IF EXISTS es_insert_dataset on public.dataset;
DROP FUNCTION public.insert_dataset_data();
DROP TRIGGER IF EXISTS es_udpate_dataset_file_name on public.attachment;
DROP FUNCTION public.udpate_dataset_file_name;

DROP TRIGGER IF EXISTS es_update_dataset on public.dataset;
DROP FUNCTION public.update_dataset;

DROP TRIGGER IF EXISTS es_delete_dataset on public.dataset;
DROP FUNCTION public.delete_dataset;


CREATE FOREIGN TABLE public.dataset_es
(
id bigint NOT NULL,
title character varying(255),
status integer,
category character varying(255),
description text,
download_times bigint,
license character varying(255),
task character varying(255),
release_id bigint,
user_id bigint,
repo_id bigint,
created_unix bigint,
updated_unix bigint,
file_name text,
file_desc text
)SERVER multicorn_es
OPTIONS
(
host '192.168.207.94',
port '9200',
index 'dataset-es-index',
rowid_column 'id',
default_sort '_id'
)
;
DELETE FROM public.dataset_es;
INSERT INTO public.dataset_es(
id,
title,
status,
category,
description,
download_times,
license, task,
release_id,
user_id,
repo_id,
created_unix,
updated_unix,
file_name,
file_desc
)
SELECT
b.id,
b.title,
b.status,
b.category,
b.description,
b.download_times,
b.license,
b.task,
b.release_id,
b.user_id,
b.repo_id,
b.created_unix,
b.updated_unix,
(select array_to_string(array_agg(name order by created_unix desc),'-#,#-') from public.attachment a where a.dataset_id=b.id and a.is_private=false),
(select array_to_string(array_agg(description order by created_unix desc),'-#,#-') from public.attachment a where a.dataset_id=b.id and a.is_private=false)
FROM public.dataset b,public.repository c where b.repo_id=c.id and c.is_private=false;


DROP TRIGGER IF EXISTS es_insert_dataset on public.dataset;

CREATE OR REPLACE FUNCTION public.insert_dataset_data() RETURNS trigger AS
$def$
DECLARE
privateValue boolean=false;
BEGIN
select into privateValue is_private from public.repository where id=NEW.repo_id;
if not privateValue then
INSERT INTO public.dataset_es(
id,
title,
status,
category,
description,
download_times,
license,
task,
release_id,
user_id,
repo_id,
created_unix,
updated_unix)
VALUES (
NEW.id,
NEW.title,
NEW.status,
NEW.category,
NEW.description,
NEW.download_times,
NEW.license,
NEW.task,
NEW.release_id,
NEW.user_id,
NEW.repo_id,
NEW.created_unix,
NEW.updated_unix
);
end if;
RETURN NEW;
END;
$def$
LANGUAGE plpgsql;



CREATE TRIGGER es_insert_dataset
AFTER INSERT ON public.dataset
FOR EACH ROW EXECUTE PROCEDURE insert_dataset_data();

ALTER TABLE public.dataset ENABLE ALWAYS TRIGGER es_insert_dataset;


DROP TRIGGER IF EXISTS es_udpate_dataset_file_name on public.attachment;

CREATE OR REPLACE FUNCTION public.udpate_dataset_file_name() RETURNS trigger AS
$def$
BEGIN
if (TG_OP = 'UPDATE') then
update public.dataset_es SET file_desc=(select array_to_string(array_agg(description order by created_unix desc),'-#,#-') from public.attachment where dataset_id=NEW.dataset_id and is_private=false) where id=NEW.dataset_id;
elsif (TG_OP = 'INSERT') then
update public.dataset_es SET file_name=(select array_to_string(array_agg(name order by created_unix desc),'-#,#-') from public.attachment where dataset_id=NEW.dataset_id and is_private=false) where id=NEW.dataset_id;
elsif (TG_OP = 'DELETE') then
update public.dataset_es SET file_name=(select array_to_string(array_agg(name order by created_unix desc),'-#,#-') from public.attachment where dataset_id=OLD.dataset_id and is_private=false) where id=OLD.dataset_id;
update public.dataset_es SET file_desc=(select array_to_string(array_agg(description order by created_unix desc),'-#,#-') from public.attachment where dataset_id=OLD.dataset_id and is_private=false) where id=OLD.dataset_id;
end if;
return NEW;
END;
$def$
LANGUAGE plpgsql;


CREATE TRIGGER es_udpate_dataset_file_name
AFTER INSERT OR UPDATE OR DELETE ON public.attachment
FOR EACH ROW EXECUTE PROCEDURE udpate_dataset_file_name();

ALTER TABLE public.attachment ENABLE ALWAYS TRIGGER es_udpate_dataset_file_name;

DROP TRIGGER IF EXISTS es_update_dataset on public.dataset;

CREATE OR REPLACE FUNCTION public.update_dataset() RETURNS trigger AS
$def$
BEGIN
UPDATE public.dataset_es
SET description=NEW.description,
title=NEW.title,
category=NEW.category,
task=NEW.task,
download_times=NEW.download_times,
updated_unix=NEW.updated_unix,
file_name=(select array_to_string(array_agg(name order by created_unix desc),'-#,#-') from public.attachment where dataset_id=NEW.id and is_private=false),
file_desc=(select array_to_string(array_agg(description order by created_unix desc),'-#,#-') from public.attachment where dataset_id=NEW.id and is_private=false)
where id=NEW.id;
return new;
END
$def$
LANGUAGE plpgsql;

CREATE TRIGGER es_update_dataset
AFTER UPDATE ON public.dataset
FOR EACH ROW EXECUTE PROCEDURE update_dataset();

ALTER TABLE public.dataset ENABLE ALWAYS TRIGGER es_update_dataset;

DROP TRIGGER IF EXISTS es_delete_dataset on public.dataset;

CREATE OR REPLACE FUNCTION public.delete_dataset() RETURNS trigger AS
$def$
declare
BEGIN
DELETE FROM public.dataset_es where id=OLD.id;
return new;
END
$def$
LANGUAGE plpgsql;


CREATE TRIGGER es_delete_dataset
AFTER DELETE ON public.dataset
FOR EACH ROW EXECUTE PROCEDURE delete_dataset();

ALTER TABLE public.dataset ENABLE ALWAYS TRIGGER es_delete_dataset;

+ 227
- 0
models/dbsql/issue_foreigntable_for_es.sql View File

@@ -0,0 +1,227 @@
delete from public.issue_es;
DROP FOREIGN TABLE public.issue_es;
DROP TRIGGER IF EXISTS es_insert_issue on public.issue;
DROP FUNCTION public.insert_issue_data;
DROP TRIGGER IF EXISTS es_udpate_issue_comment on public.comment;
DROP FUNCTION udpate_issue_comment;
DROP TRIGGER IF EXISTS es_update_issue on public.issue;
DROP FUNCTION public.update_issue;
DROP TRIGGER IF EXISTS es_delete_issue on public.issue;
DROP FUNCTION public.delete_issue;


CREATE FOREIGN TABLE public.issue_es
(
id bigint NOT NULL,
repo_id bigint,
index bigint,
poster_id bigint,
original_author character varying(255),
original_author_id bigint,
name character varying(255) ,
content text,
comment text,
milestone_id bigint,
priority integer,
is_closed boolean,
is_pull boolean,
pr_id bigint,
num_comments integer,
ref character varying(255),
deadline_unix bigint,
created_unix bigint,
updated_unix bigint,
closed_unix bigint,
is_locked boolean NOT NULL,
amount bigint,
is_transformed boolean NOT NULL
)SERVER multicorn_es
OPTIONS
(
host '192.168.207.94',
port '9200',
index 'issue-es-index',
rowid_column 'id',
default_sort '_id'
)
;

delete from public.issue_es;
INSERT INTO public.issue_es(
id,
repo_id,
index,
poster_id,
original_author,
original_author_id,
name,
content,
milestone_id,
priority,
is_closed,
is_pull,
num_comments,
ref,
deadline_unix,
created_unix,
updated_unix,
closed_unix,
is_locked,
amount,
is_transformed,comment,pr_id)
SELECT
b.id,
b.repo_id,
b.index,
b.poster_id,
b.original_author,
b.original_author_id,
b.name,
b.content,
b.milestone_id,
b.priority,
b.is_closed,
b.is_pull,
b.num_comments,
b.ref,
b.deadline_unix,
b.created_unix,
b.updated_unix,
b.closed_unix,
b.is_locked,
b.amount,
b.is_transformed,
(select array_to_string(array_agg(content order by created_unix desc),',') from public.comment a where a.issue_id=b.id),
(select id from public.pull_request d where b.id=d.issue_id and b.is_pull=true)
FROM public.issue b,public.repository c where b.repo_id=c.id and c.is_private=false;


CREATE OR REPLACE FUNCTION public.insert_issue_data() RETURNS trigger AS
$def$
DECLARE
privateValue boolean=false;
BEGIN
select into privateValue is_private from public.repository where id=NEW.repo_id;
if not privateValue then
INSERT INTO public.issue_es(
id,
repo_id,
index,
poster_id,
original_author,
original_author_id,
name,
content,
milestone_id,
priority,
is_closed,
is_pull,
num_comments,
ref,
deadline_unix,
created_unix,
updated_unix,
closed_unix,
is_locked,
amount,
is_transformed)
VALUES (
NEW.id,
NEW.repo_id,
NEW.index,
NEW.poster_id,
NEW.original_author,
NEW.original_author_id,
NEW.name,
NEW.content,
NEW.milestone_id,
NEW.priority,
NEW.is_closed,
NEW.is_pull,
NEW.num_comments,
NEW.ref,
NEW.deadline_unix,
NEW.created_unix,
NEW.updated_unix,
NEW.closed_unix,
NEW.is_locked,
NEW.amount,
NEW.is_transformed
);
end if;
RETURN NEW;
END;
$def$
LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS es_insert_issue on public.issue;

CREATE TRIGGER es_insert_issue
AFTER INSERT ON public.issue
FOR EACH ROW EXECUTE PROCEDURE insert_issue_data();

ALTER TABLE public.issue ENABLE ALWAYS TRIGGER es_insert_issue;

CREATE OR REPLACE FUNCTION public.udpate_issue_comment() RETURNS trigger AS
$def$
BEGIN
if (TG_OP = 'DELETE') then
update public.issue_es SET comment=(select array_to_string(array_agg(content order by created_unix desc),',') from public.comment where issue_id=OLD.issue_id) where id=OLD.issue_id;
elsif (TG_OP = 'UPDATE') then
update public.issue_es SET comment=(select array_to_string(array_agg(content order by created_unix desc),',') from public.comment where issue_id=NEW.issue_id) where id=NEW.issue_id;
end if;
return null;
END;
$def$
LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS es_udpate_issue_comment on public.comment;
CREATE TRIGGER es_udpate_issue_comment
AFTER DELETE OR UPDATE ON public.comment
FOR EACH ROW EXECUTE PROCEDURE udpate_issue_comment();

ALTER TABLE public.comment ENABLE ALWAYS TRIGGER es_udpate_issue_comment;


CREATE OR REPLACE FUNCTION public.update_issue() RETURNS trigger AS
$def$
declare
BEGIN
UPDATE public.issue_es
SET content=NEW.content,
name=NEW.name,
is_closed=NEW.is_closed,
num_comments=NEW.num_comments,
updated_unix=NEW.updated_unix,
comment=(select array_to_string(array_agg(content order by created_unix desc),',') from public.comment where issue_id=NEW.id)
where id=NEW.id;
return new;
END
$def$
LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS es_update_issue on public.issue;

CREATE TRIGGER es_update_issue
AFTER UPDATE ON public.issue
FOR EACH ROW EXECUTE PROCEDURE update_issue();

ALTER TABLE public.issue ENABLE ALWAYS TRIGGER es_update_issue;

CREATE OR REPLACE FUNCTION public.delete_issue() RETURNS trigger AS
$def$
declare
BEGIN
DELETE FROM public.issue_es where id=OLD.id;
return new;
END
$def$
LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS es_delete_issue on public.issue;
CREATE TRIGGER es_delete_issue
AFTER DELETE ON public.issue
FOR EACH ROW EXECUTE PROCEDURE delete_issue();

ALTER TABLE public.issue ENABLE ALWAYS TRIGGER es_delete_issue;

+ 545
- 0
models/dbsql/repo_foreigntable_for_es.sql View File

@@ -0,0 +1,545 @@
-- 要处理项目从私有变为公有,并且从公有变成私有的情况
DELETE FROM public.repository_es;
DROP FOREIGN table if exists public.repository_es;
DROP TRIGGER IF EXISTS es_insert_repository on public.repository;
DROP FUNCTION public.insert_repository_data;
DROP TRIGGER IF EXISTS es_update_repository on public.repository;
DROP FUNCTION public.update_repository;

DROP TRIGGER IF EXISTS es_delete_repository on public.repository;
DROP FUNCTION public.delete_repository;

DROP TRIGGER IF EXISTS es_udpate_repository_lang on public.language_stat;
DROP FUNCTION public.udpate_repository_lang;


CREATE FOREIGN TABLE public.repository_es (
id bigint NOT NULL,
owner_id bigint,
owner_name character varying(255),
lower_name character varying(255) NOT NULL,
name character varying(255) NOT NULL,
description text,
website character varying(2048),
original_service_type integer,
original_url character varying(2048),
default_branch character varying(255),
num_watches integer,
num_stars integer,
num_forks integer,
num_issues integer,
num_closed_issues integer,
num_pulls integer,
num_closed_pulls integer,
num_milestones integer DEFAULT 0 NOT NULL,
num_closed_milestones integer DEFAULT 0 NOT NULL,
is_private boolean,
is_empty boolean,
is_archived boolean,
is_mirror boolean,
status integer DEFAULT 0 NOT NULL,
is_fork boolean DEFAULT false NOT NULL,
fork_id bigint,
is_template boolean DEFAULT false NOT NULL,
template_id bigint,
size bigint DEFAULT 0 NOT NULL,
is_fsck_enabled boolean DEFAULT true NOT NULL,
close_issues_via_commit_in_any_branch boolean DEFAULT false NOT NULL,
topics text,
avatar character varying(64),
created_unix bigint,
updated_unix bigint,
contract_address character varying(255),
block_chain_status integer DEFAULT 0 NOT NULL,
balance character varying(255) DEFAULT '0'::character varying NOT NULL,
clone_cnt bigint DEFAULT 0 NOT NULL,
license character varying(100),
download_cnt bigint DEFAULT 0 NOT NULL,
num_commit bigint DEFAULT 0 NOT NULL,
git_clone_cnt bigint DEFAULT 0 NOT NULL,
creator_id bigint NOT NULL DEFAULT 0,
repo_type integer NOT NULL DEFAULT 0,
lang character varying(2048),
alias character varying(255),
lower_alias character varying(255)
) SERVER multicorn_es
OPTIONS
(
host '192.168.207.94',
port '9200',
index 'repository-es-index',
rowid_column 'id',
default_sort '_id'
)
;
delete from public.repository_es;
INSERT INTO public.repository_es (id,
owner_id,
owner_name,
lower_name,
name,
description,
website,
original_service_type,
original_url,
default_branch,
num_watches,
num_stars,
num_forks,
num_issues,
num_closed_issues,
num_pulls,
num_closed_pulls,
num_milestones,
num_closed_milestones,
is_private,
is_empty,
is_archived,
is_mirror,
status,
is_fork,
fork_id,
is_template,
template_id,
size,
is_fsck_enabled,
close_issues_via_commit_in_any_branch,
topics,
avatar,
created_unix,
updated_unix,
contract_address,
block_chain_status,
balance,
clone_cnt,
num_commit,
git_clone_cnt,
creator_id,
repo_type,
lang,
alias,
lower_alias
)
SELECT
id,
owner_id,
owner_name,
lower_name,
name,
description,
website,
original_service_type,
original_url,
default_branch,
num_watches,
num_stars,
num_forks,
num_issues,
num_closed_issues,
num_pulls,
num_closed_pulls,
num_milestones,
num_closed_milestones,
is_private,
is_empty,
is_archived,
is_mirror,
status,
is_fork,
fork_id,
is_template,
template_id,
size,
is_fsck_enabled,
close_issues_via_commit_in_any_branch,
topics,
avatar,
created_unix,
updated_unix,
contract_address,
block_chain_status,
balance,
clone_cnt,
num_commit,
git_clone_cnt,
creator_id,
repo_type,
(select array_to_string(array_agg(language order by percentage desc),',') from public.language_stat a where a.repo_id=b.id),
alias,
lower_alias
FROM public.repository b where b.is_private=false;

DROP TRIGGER IF EXISTS es_insert_repository on public.repository;

CREATE OR REPLACE FUNCTION public.insert_repository_data() RETURNS trigger AS
$def$
BEGIN
if not NEW.is_private then
INSERT INTO public.repository_es (id,
owner_id,
owner_name,
lower_name,
name,
description,
website,
original_service_type,
original_url,
default_branch,
num_watches,
num_stars,
num_forks,
num_issues,
num_closed_issues,
num_pulls,
num_closed_pulls,
num_milestones,
num_closed_milestones,
is_private,
is_empty,
is_archived,
is_mirror,
status,
is_fork,
fork_id,
is_template,
template_id,
size,
is_fsck_enabled,
close_issues_via_commit_in_any_branch,
topics,
avatar,
created_unix,
updated_unix,
contract_address,
block_chain_status,
balance,
clone_cnt,
num_commit,
git_clone_cnt,
creator_id,
repo_type,
alias,
lower_alias) VALUES
(NEW.id,
NEW.owner_id,
NEW.owner_name,
NEW.lower_name,
NEW.name,
NEW.description,
NEW.website,
NEW.original_service_type,
NEW.original_url,
NEW.default_branch,
NEW.num_watches,
NEW.num_stars,
NEW.num_forks,
NEW.num_issues,
NEW.num_closed_issues,
NEW.num_pulls,
NEW.num_closed_pulls,
NEW.num_milestones,
NEW.num_closed_milestones,
NEW.is_private,
NEW.is_empty,
NEW.is_archived,
NEW.is_mirror,
NEW.status,
NEW.is_fork,
NEW.fork_id,
NEW.is_template,
NEW.template_id,
NEW.size,
NEW.is_fsck_enabled,
NEW.close_issues_via_commit_in_any_branch,
NEW.topics,
NEW.avatar,
NEW.created_unix,
NEW.updated_unix,
NEW.contract_address,
NEW.block_chain_status,
NEW.balance,
NEW.clone_cnt,
NEW.num_commit,
NEW.git_clone_cnt,
NEW.creator_id,
NEW.repo_type,
NEW.alias,
NEW.lower_alias);
end if;
RETURN NEW;
END;
$def$
LANGUAGE plpgsql;


CREATE TRIGGER es_insert_repository
AFTER INSERT ON public.repository
FOR EACH ROW EXECUTE PROCEDURE insert_repository_data();

ALTER TABLE public.repository ENABLE ALWAYS TRIGGER es_insert_repository;

DROP TRIGGER IF EXISTS es_update_repository on public.repository;

CREATE OR REPLACE FUNCTION public.update_repository() RETURNS trigger AS
$def$
BEGIN
if OLD.is_private != NEW.is_private then
if OLD.is_private and not NEW.is_private then
--insert
INSERT INTO public.repository_es (id,
owner_id,
owner_name,
lower_name,
name,
description,
website,
original_service_type,
original_url,
default_branch,
num_watches,
num_stars,
num_forks,
num_issues,
num_closed_issues,
num_pulls,
num_closed_pulls,
num_milestones,
num_closed_milestones,
is_private,
is_empty,
is_archived,
is_mirror,
status,
is_fork,
fork_id,
is_template,
template_id,
size,
is_fsck_enabled,
close_issues_via_commit_in_any_branch,
topics,
avatar,
created_unix,
updated_unix,
contract_address,
block_chain_status,
balance,
clone_cnt,
num_commit,
git_clone_cnt,
creator_id,
repo_type,
lang,
alias,
lower_alias)
SELECT
id,
owner_id,
owner_name,
lower_name,
name,
description,
website,
original_service_type,
original_url,
default_branch,
num_watches,
num_stars,
num_forks,
num_issues,
num_closed_issues,
num_pulls,
num_closed_pulls,
num_milestones,
num_closed_milestones,
is_private,
is_empty,
is_archived,
is_mirror,
status,
is_fork,
fork_id,
is_template,
template_id,
size,
is_fsck_enabled,
close_issues_via_commit_in_any_branch,
topics,
avatar,
created_unix,
updated_unix,
contract_address,
block_chain_status,
balance,
clone_cnt,
num_commit,
git_clone_cnt,
creator_id,
repo_type,
(select array_to_string(array_agg(language order by percentage desc),',') from public.language_stat a where a.repo_id=b.id),
alias,
lower_alias
FROM public.repository b where b.id=NEW.id;
INSERT INTO public.dataset_es(
id,
title,
status,
category,
description,
download_times,
license, task,
release_id,
user_id,
repo_id,
created_unix,
updated_unix,file_name)
SELECT
b.id,
b.title,
b.status,
b.category,
b.description,
b.download_times,
b.license,
b.task,
b.release_id,
b.user_id,
b.repo_id,
b.created_unix,
b.updated_unix,(select array_to_string(array_agg(name order by created_unix desc),',') from public.attachment a where a.dataset_id=b.id and a.is_private=false)
FROM public.dataset b where b.repo_id=NEW.id;

INSERT INTO public.issue_es(
id,
repo_id,
index,
poster_id,
original_author,
original_author_id,
name,
content,
milestone_id,
priority,
is_closed,
is_pull,
num_comments,
ref,
deadline_unix,
created_unix,
updated_unix,
closed_unix,
is_locked,
amount,
is_transformed,comment,pr_id)
SELECT
b.id,
b.repo_id,
b.index,
b.poster_id,
b.original_author,
b.original_author_id,
b.name,
b.content,
b.milestone_id,
b.priority,
b.is_closed,
b.is_pull,
b.num_comments,
b.ref,
b.deadline_unix,
b.created_unix,
b.updated_unix,
b.closed_unix,
b.is_locked,
b.amount,
b.is_transformed,
(select array_to_string(array_agg(content order by created_unix desc),',') from public.comment a where a.issue_id=b.id),
(select id from public.pull_request d where d.issue_id=b.id)
FROM public.issue b where b.repo_id=NEW.id;
end if;

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

end if;

if not NEW.is_private then
raise notice 'update repo,the updated_unix is %',NEW.updated_unix;
update public.repository_es SET description=NEW.description,
name=NEW.name,
lower_name=NEW.lower_name,
owner_name=NEW.owner_name,
website=NEW.website,
updated_unix=NEW.updated_unix,
num_watches=NEW.num_watches,
num_stars=NEW.num_stars,
num_forks=NEW.num_forks,
topics=NEW.topics,
alias = NEW.alias,
lower_alias = NEW.lower_alias,
avatar=NEW.avatar
where id=NEW.id;
end if;
return new;
END
$def$
LANGUAGE plpgsql;

CREATE TRIGGER es_update_repository
AFTER UPDATE ON public.repository
FOR EACH ROW EXECUTE PROCEDURE update_repository();

ALTER TABLE public.repository ENABLE ALWAYS TRIGGER es_update_repository;


DROP TRIGGER IF EXISTS es_delete_repository on public.repository;

CREATE OR REPLACE FUNCTION public.delete_repository() RETURNS trigger AS
$def$
declare
BEGIN
delete from public.issue_es where repo_id=OLD.id;
delete from public.dataset_es where repo_id=OLD.id;
DELETE FROM public.repository_es where id=OLD.id;
return new;
END
$def$
LANGUAGE plpgsql;


CREATE TRIGGER es_delete_repository
AFTER DELETE ON public.repository
FOR EACH ROW EXECUTE PROCEDURE delete_repository();

ALTER TABLE public.repository ENABLE ALWAYS TRIGGER es_delete_repository;



DROP TRIGGER IF EXISTS es_udpate_repository_lang on public.language_stat;

CREATE OR REPLACE FUNCTION public.udpate_repository_lang() RETURNS trigger AS
$def$
BEGIN
if (TG_OP = 'UPDATE') then
update public.repository_es SET lang=(select array_to_string(array_agg(language order by percentage desc),',') from public.language_stat where repo_id=NEW.repo_id) where id=NEW.repo_id;
elsif (TG_OP = 'INSERT') then
update public.repository_es SET lang=(select array_to_string(array_agg(language order by percentage desc),',') from public.language_stat where repo_id=NEW.repo_id) where id=NEW.repo_id;
elsif (TG_OP = 'DELETE') then
if exists(select 1 from public.repository where id=OLD.repo_id) then
update public.repository_es SET lang=(select array_to_string(array_agg(language order by percentage desc),',') from public.language_stat where repo_id=OLD.repo_id) where id=OLD.repo_id;
end if;
end if;
return null;
END;
$def$
LANGUAGE plpgsql;

CREATE TRIGGER es_udpate_repository_lang
AFTER INSERT OR UPDATE OR DELETE ON public.language_stat
FOR EACH ROW EXECUTE PROCEDURE udpate_repository_lang();

ALTER TABLE public.language_stat ENABLE ALWAYS TRIGGER es_udpate_repository_lang;

+ 317
- 0
models/dbsql/user_foreigntable_for_es.sql View File

@@ -0,0 +1,317 @@
DELETE FROM public.user_es;
DROP FOREIGN table if exists public.user_es;
DROP TRIGGER IF EXISTS es_insert_user on public.user;
DROP FUNCTION public.insert_user_data;
DROP TRIGGER IF EXISTS es_update_user on public.user;
DROP FUNCTION public.update_user;

DROP TRIGGER IF EXISTS es_delete_user on public.user;
DROP FUNCTION public.delete_user;

CREATE FOREIGN TABLE public.user_es
(
id bigint NOT NULL ,
lower_name character varying(255) NULL,
name character varying(255) NULL,
full_name character varying(255),
email character varying(255),
keep_email_private boolean,
email_notifications_preference character varying(20) ,
passwd character varying(255) ,
passwd_hash_algo character varying(255) ,
must_change_password boolean NOT NULL DEFAULT false,
login_type integer,
login_source bigint NOT NULL DEFAULT 0,
login_name character varying(255) ,
type integer,
location character varying(255),
website character varying(255),
rands character varying(10),
salt character varying(10),
language character varying(5),
description character varying(255),
created_unix bigint,
updated_unix bigint,
last_login_unix bigint,
last_repo_visibility boolean,
max_repo_creation integer,
is_active boolean,
is_admin boolean,
is_restricted boolean NOT NULL DEFAULT false,
allow_git_hook boolean,
allow_import_local boolean,
allow_create_organization boolean DEFAULT true,
prohibit_login boolean NOT NULL DEFAULT false,
avatar character varying(2048) ,
avatar_email character varying(255),
use_custom_avatar boolean,
num_followers integer,
num_following integer NOT NULL DEFAULT 0,
num_stars integer,
num_repos integer,
num_teams integer,
num_members integer,
visibility integer NOT NULL DEFAULT 0,
repo_admin_change_team_access boolean NOT NULL DEFAULT false,
diff_view_style character varying(255),
theme character varying(255),
token character varying(1024) ,
public_key character varying(255),
private_key character varying(255),
is_operator boolean NOT NULL DEFAULT false,
num_dataset_stars integer NOT NULL DEFAULT 0
) SERVER multicorn_es
OPTIONS
(
host '192.168.207.94',
port '9200',
index 'user-es-index',
rowid_column 'id',
default_sort '_id'
)
;
delete from public.user_es;
INSERT INTO public.user_es(
id,
lower_name,
name,
full_name,
email,
keep_email_private,
email_notifications_preference,
must_change_password,
login_type,
login_source,
login_name,
type,
location,
website,
rands,
language,
description,
created_unix,
updated_unix,
last_login_unix,
last_repo_visibility,
max_repo_creation,
is_active,
is_restricted,
allow_git_hook,
allow_import_local,
allow_create_organization,
prohibit_login,
avatar,
avatar_email,
use_custom_avatar,
num_followers,
num_following,
num_stars,
num_repos,
num_teams,
num_members,
visibility,
repo_admin_change_team_access,
diff_view_style,
theme,
is_operator,
num_dataset_stars)
SELECT
id,
lower_name,
name,
full_name,
email,
keep_email_private,
email_notifications_preference,
must_change_password,
login_type,
login_source,
login_name,
type,
location,
website,
rands,
language,
description,
created_unix,
updated_unix,
last_login_unix,
last_repo_visibility,
max_repo_creation,
is_active,
is_restricted,
allow_git_hook,
allow_import_local,
allow_create_organization,
prohibit_login,
avatar,
avatar_email,
use_custom_avatar,
num_followers,
num_following,
num_stars,
num_repos,
num_teams,
num_members,
visibility,
repo_admin_change_team_access,
diff_view_style,
theme,
is_operator,
num_dataset_stars
FROM public.user;

DROP TRIGGER IF EXISTS es_insert_user on public.user;

CREATE OR REPLACE FUNCTION public.insert_user_data() RETURNS trigger AS
$def$
BEGIN
INSERT INTO public."user_es"(
id,
lower_name,
name,
full_name,
email,
keep_email_private,
email_notifications_preference,
must_change_password,
login_type,
login_source,
login_name,
type,
location,
website,
rands,
language,
description,
created_unix,
updated_unix,
last_login_unix,
last_repo_visibility,
max_repo_creation,
is_active,
is_restricted,
allow_git_hook,
allow_import_local,
allow_create_organization,
prohibit_login,
avatar,
avatar_email,
use_custom_avatar,
num_followers,
num_following,
num_stars,
num_repos,
num_teams,
num_members,
visibility,
repo_admin_change_team_access,
diff_view_style,
theme,
is_operator,
num_dataset_stars)
VALUES (
NEW.id,
NEW.lower_name,
NEW.name,
NEW.full_name,
NEW.email,
NEW.keep_email_private,
NEW.email_notifications_preference,
NEW.must_change_password,
NEW.login_type,
NEW.login_source,
NEW.login_name,
NEW.type,
NEW.location,
NEW.website,
NEW.rands,
NEW.language,
NEW.description,
NEW.created_unix,
NEW.updated_unix,
NEW.last_login_unix,
NEW.last_repo_visibility,
NEW.max_repo_creation,
NEW.is_active,
NEW.is_restricted,
NEW.allow_git_hook,
NEW.allow_import_local,
NEW.allow_create_organization,
NEW.prohibit_login,
NEW.avatar,
NEW.avatar_email,
NEW.use_custom_avatar,
NEW.num_followers,
NEW.num_following,
NEW.num_stars,
NEW.num_repos,
NEW.num_teams,
NEW.num_members,
NEW.visibility,
NEW.repo_admin_change_team_access,
NEW.diff_view_style,
NEW.theme,
NEW.is_operator,
NEW.num_dataset_stars
);

RETURN NEW;
END;
$def$
LANGUAGE plpgsql;



CREATE TRIGGER es_insert_user
AFTER INSERT ON public.user
FOR EACH ROW EXECUTE PROCEDURE insert_user_data();

ALTER TABLE public.user ENABLE ALWAYS TRIGGER es_insert_user;

DROP TRIGGER IF EXISTS es_update_user on public.user;

CREATE OR REPLACE FUNCTION public.update_user() RETURNS trigger AS
$def$
BEGIN
UPDATE public.user_es
SET description=NEW.description,
name=NEW.name,
full_name=NEW.full_name,
location=NEW.location,
website=NEW.website,
email=NEW.email,
num_dataset_stars=NEW.num_dataset_stars,
updated_unix=NEW.updated_unix
where id=NEW.id;
return new;
END
$def$
LANGUAGE plpgsql;



CREATE TRIGGER es_update_user
AFTER UPDATE ON public.user
FOR EACH ROW EXECUTE PROCEDURE update_user();

ALTER TABLE public.user ENABLE ALWAYS TRIGGER es_update_user;

DROP TRIGGER IF EXISTS es_delete_user on public.user;

CREATE OR REPLACE FUNCTION public.delete_user() RETURNS trigger AS
$def$
declare
BEGIN
DELETE FROM public.user_es where id=OLD.id;
return new;
END
$def$
LANGUAGE plpgsql;


CREATE TRIGGER es_delete_user
AFTER DELETE ON public.user
FOR EACH ROW EXECUTE PROCEDURE delete_user();
ALTER TABLE public.user ENABLE ALWAYS TRIGGER es_delete_user;

+ 0
- 5
models/file_chunk.go View File

@@ -13,11 +13,6 @@ const (
FileUploaded FileUploaded
) )


const (
TypeCloudBrainOne int = iota
TypeCloudBrainTwo
)

type FileChunk struct { type FileChunk struct {
ID int64 `xorm:"pk autoincr"` ID int64 `xorm:"pk autoincr"`
UUID string `xorm:"uuid UNIQUE"` UUID string `xorm:"uuid UNIQUE"`


+ 4
- 0
models/models.go View File

@@ -138,6 +138,8 @@ func init() {
new(OfficialTag), new(OfficialTag),
new(OfficialTagRepos), new(OfficialTagRepos),
new(WechatBindLog), new(WechatBindLog),
new(OrgStatistic),
new(SearchRecord),
) )


tablesStatistic = append(tablesStatistic, tablesStatistic = append(tablesStatistic,
@@ -152,6 +154,8 @@ func init() {
new(UserBusinessAnalysisCurrentWeek), new(UserBusinessAnalysisCurrentWeek),
new(UserBusinessAnalysisYesterday), new(UserBusinessAnalysisYesterday),
new(UserLoginLog), new(UserLoginLog),
new(UserMetrics),
new(UserAnalysisPara),
) )


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


+ 99
- 0
models/org.go View File

@@ -8,6 +8,7 @@ package models
import ( import (
"fmt" "fmt"
"os" "os"
"strconv"
"strings" "strings"


"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
@@ -19,6 +20,17 @@ import (
"xorm.io/xorm" "xorm.io/xorm"
) )


type OrgStatistic struct {
ID int64 `xorm:"pk autoincr"`
OrgID int64 `xorm:"UNIQUE"`
NumScore int `xorm:"INDEX NOT NULL DEFAULT 0"`
}

type OrgScore struct {
*User
Score string
}

// IsOwnedBy returns true if given user is in the owner team. // IsOwnedBy returns true if given user is in the owner team.
func (org *User) IsOwnedBy(uid int64) (bool, error) { func (org *User) IsOwnedBy(uid int64) (bool, error) {
return IsOrganizationOwner(org.ID, uid) return IsOrganizationOwner(org.ID, uid)
@@ -135,6 +147,93 @@ func (org *User) RemoveOrgRepo(repoID int64) error {
return org.removeOrgRepo(x, repoID) return org.removeOrgRepo(x, repoID)
} }


func UpdateOrgStatistics() {
ids, err := GetOrganizationsId()
if err != nil {
return
}
for _, id := range ids {
org := User{ID: id}
orgStat := &OrgStatistic{OrgID: id}
numScore, err := org.getOrgStatistics()
if err == nil {
has, _ := x.Get(orgStat)

orgStat.NumScore = numScore
if has {
x.ID(orgStat.ID).Cols("num_score").Update(&orgStat)
} else {
x.Insert(orgStat)
}

}
}

}

func (org *User) getOrgStatistics() (int, error) {
count, err := getRepositoryCount(x, org)
if err != nil {
return 0, err
}

err = org.GetRepositories(ListOptions{int(count), 1})

if err != nil {
return 0, err
}
var numScore = 0
for _, repo := range org.Repos {

numScore += int(getOpenIByRepoId(repo.ID))
}

return numScore, nil

}

func FindTopNStarsOrgs(n int) ([]*OrgScore, error) {
sql := "select a.id,sum(b.num_stars) score from \"user\" a ,repository b where a.id=b.owner_id and a.type=1 group by a.id order by score desc limit " + strconv.Itoa(n)

return findTopNOrgs(sql)
}
func FindTopNMembersOrgs(n int) ([]*OrgScore, error) {
sql := "select id, count(user_id) score from" +
" (select org_id as id, uid as user_id from org_user " +
"union select a.id,b.user_id from \"user\" a,collaboration b,repository c " +
"where a.type=1 and a.id=c.owner_id and b.repo_id=c.id) d " +
"group by id order by score desc limit " + strconv.Itoa(n)

return findTopNOrgs(sql)
}

func FindTopNOpenIOrgs(n int) ([]*OrgScore, error) {
sql := "select org_id id,num_score score from org_statistic order by num_score desc limit 10" + strconv.Itoa(n)

return findTopNOrgs(sql)
}

func findTopNOrgs(sql string) ([]*OrgScore, error) {
resutls, err := x.QueryString(sql)

if err != nil {
return nil, err
}
var orgScore []*OrgScore
for _, record := range resutls {
id, _ := strconv.ParseInt(record["id"], 10, 64)
user, err := getUserByID(x, id)
if err != nil {
continue
}
orgScore = append(orgScore, &OrgScore{user, record["score"]})

}

return orgScore, nil

}

// CreateOrganization creates record of a new organization. // CreateOrganization creates record of a new organization.
func CreateOrganization(org, owner *User) (err error) { func CreateOrganization(org, owner *User) (err error) {
if !owner.CanCreateOrganization() { if !owner.CanCreateOrganization() {


+ 10
- 7
models/repo.go View File

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


import ( import (
"code.gitea.io/gitea/modules/git"
"context" "context"
"crypto/md5" "crypto/md5"
"errors" "errors"
"fmt" "fmt"
"html/template" "html/template"
"math/rand" "math/rand"

"code.gitea.io/gitea/modules/git"
"xorm.io/xorm" "xorm.io/xorm"


"code.gitea.io/gitea/modules/blockchain" "code.gitea.io/gitea/modules/blockchain"
@@ -1606,14 +1607,16 @@ func updateRepository(e Engine, repo *Repository, visibilityChanged bool) (err e
} }


dataset, err := GetDatasetByRepo(repo) dataset, err := GetDatasetByRepo(repo)
if err != nil {
if err != nil && !IsErrNotExist(err) {
return err return err
} }
_, err = e.Where("dataset_id = ?", dataset.ID).Cols("is_private").Update(&Attachment{
IsPrivate: true,
})
if err != nil {
return err
if dataset != nil {
_, err = e.Where("dataset_id = ?", dataset.ID).Cols("is_private").Update(&Attachment{
IsPrivate: true,
})
if err != nil {
return err
}
} }


} else { } else {


+ 7
- 3
models/repo_list.go View File

@@ -190,7 +190,8 @@ type SearchRepoOptions struct {
// None -> include all repos // None -> include all repos
// True -> include just courses // True -> include just courses
// False -> include just no courses // False -> include just no courses
Course util.OptionalBool
Course util.OptionalBool
OnlySearchPrivate bool
} }


//SearchOrderBy is used to sort the result //SearchOrderBy is used to sort the result
@@ -219,12 +220,15 @@ const (
SearchOrderByDownloadTimes SearchOrderBy = "download_times DESC" SearchOrderByDownloadTimes SearchOrderBy = "download_times DESC"
SearchOrderByHot SearchOrderBy = "(num_watches + num_stars + num_forks + clone_cnt) DESC" SearchOrderByHot SearchOrderBy = "(num_watches + num_stars + num_forks + clone_cnt) DESC"
SearchOrderByActive SearchOrderBy = "(num_issues + num_pulls + num_commit) DESC" SearchOrderByActive SearchOrderBy = "(num_issues + num_pulls + num_commit) DESC"
SearchOrderByWatches SearchOrderBy = "num_watches DESC"
) )


// SearchRepositoryCondition creates a query condition according search repository options // SearchRepositoryCondition creates a query condition according search repository options
func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond { func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond {
var cond = builder.NewCond() var cond = builder.NewCond()

if opts.OnlySearchPrivate {
cond = cond.And(builder.Eq{"is_private": true})
}
if opts.Private { if opts.Private {
if opts.Actor != nil && !opts.Actor.IsAdmin && opts.Actor.ID != opts.OwnerID { if opts.Actor != nil && !opts.Actor.IsAdmin && opts.Actor.ID != opts.OwnerID {
// OK we're in the context of a User // OK we're in the context of a User
@@ -337,7 +341,7 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond {
if !opts.TopicOnly { if !opts.TopicOnly {
var likes = builder.NewCond() var likes = builder.NewCond()
for _, v := range strings.Split(opts.Keyword, ",") { for _, v := range strings.Split(opts.Keyword, ",") {
likes = likes.Or(builder.Like{"lower_name", strings.ToLower(v)})
likes = likes.Or(builder.Like{"lower_alias", strings.ToLower(v)})
likes = likes.Or(builder.Like{"alias", v}) likes = likes.Or(builder.Like{"alias", v})
if opts.IncludeDescription { if opts.IncludeDescription {
likes = likes.Or(builder.Like{"LOWER(description)", strings.ToLower(v)}) likes = likes.Or(builder.Like{"LOWER(description)", strings.ToLower(v)})


+ 10
- 0
models/repo_statistic.go View File

@@ -73,6 +73,16 @@ func (repo *RepoStatistic) DisplayName() string {
return repo.Alias return repo.Alias
} }


func getOpenIByRepoId(repoId int64) float64 {
repoStatistic := new(RepoStatistic)
has, err := xStatistic.Cols("radar_total").Where("repo_id=?", repoId).Desc("id").Limit(1).Get(repoStatistic)
if !has || err != nil {
return 0
}
return repoStatistic.RadarTotal

}

func DeleteRepoStatDaily(date string) error { func DeleteRepoStatDaily(date string) error {
sess := xStatistic.NewSession() sess := xStatistic.NewSession()
defer sess.Close() defer sess.Close()


+ 83
- 0
models/search_record.go View File

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

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

type SearchRecord struct {
ID int64 `xorm:"pk autoincr"`
//user
Keyword string `xorm:"NOT NULL"`
//
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
}

func SaveSearchKeywordToDb(keyword string) error {
record := &SearchRecord{
Keyword: keyword,
}
sess := x.NewSession()
defer sess.Close()
_, err := sess.Insert(record)
if err != nil {
log.Info("insert error." + err.Error())
return err
}
return nil
}

func setIssueQueryCondition(sess *xorm.Session, Keyword string, isPull bool, userId int64) {
sess.And("issue.poster_id=?", userId)
sess.And("issue.is_pull=?", isPull)
sess.And("(issue.name like '%" + Keyword + "%' or issue.content like '%" + Keyword + "%')")
sess.Join("INNER", "repository", "issue.repo_id = repository.id").And("repository.is_private = ?", true)
}

func SearchPrivateIssueOrPr(Page int, PageSize int, Keyword string, isPull bool, userId int64) ([]*Issue, int64, error) {
sess := x.NewSession()
defer sess.Close()
setIssueQueryCondition(sess, Keyword, isPull, userId)
count, err := sess.Count(new(Issue))
if err != nil {
return nil, 0, err
}

setIssueQueryCondition(sess, Keyword, isPull, userId)
sess.Desc("issue.created_unix")
sess.Limit(PageSize, (Page-1)*PageSize)
issues := make([]*Issue, 0)
if err := sess.Find(&issues); err != nil {
return nil, 0, err
} else {
return issues, count, nil
}
}

func setDataSetQueryCondition(sess *xorm.Session, Keyword string, userId int64) {
sess.And("dataset.user_id=?", userId)
sess.And("(dataset.title like '%" + Keyword + "%' or dataset.description like '%" + Keyword + "%')")
sess.Join("INNER", "repository", "dataset.repo_id = repository.id").And("repository.is_private = ?", true)
}

func SearchDatasetBySQL(Page int, PageSize int, Keyword string, userId int64) ([]*Dataset, int64, error) {
sess := x.NewSession()
defer sess.Close()
setDataSetQueryCondition(sess, Keyword, userId)
count, err := sess.Count(new(Dataset))
if err != nil {
return nil, 0, err
}

setDataSetQueryCondition(sess, Keyword, userId)
sess.Desc("dataset.created_unix")
sess.Limit(PageSize, (Page-1)*PageSize)
datasets := make([]*Dataset, 0)
if err := sess.Find(&datasets); err != nil {
return nil, 0, err
} else {
return datasets, count, nil
}

}

+ 6
- 0
models/user.go View File

@@ -2104,6 +2104,12 @@ func GetOrganizationsCount() (int64, error) {


} }


func GetOrganizationsId() ([]int64, error) {
var ids []int64
err := x.Table("user").Where("type=1").Cols("id").Find(&ids)
return ids, err
}

func GetBlockChainUnSuccessUsers() ([]*User, error) { func GetBlockChainUnSuccessUsers() ([]*User, error) {
users := make([]*User, 0, 10) users := make([]*User, 0, 10)
err := x.Where("public_key = ''"). err := x.Where("public_key = ''").


+ 394
- 172
models/user_business_analysis.go View File

@@ -6,7 +6,6 @@ import (
"strconv" "strconv"
"time" "time"


"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/timeutil"
"xorm.io/builder" "xorm.io/builder"
@@ -81,6 +80,19 @@ type UserBusinessAnalysisAll struct {
Name string `xorm:"NOT NULL"` Name string `xorm:"NOT NULL"`


DataDate string `xorm:"NULL"` DataDate string `xorm:"NULL"`

//cloudbraintask
CloudBrainTaskNum int `xorm:"NOT NULL DEFAULT 0"`
GpuDebugJob int `xorm:"NOT NULL DEFAULT 0"`
NpuDebugJob int `xorm:"NOT NULL DEFAULT 0"`
GpuTrainJob int `xorm:"NOT NULL DEFAULT 0"`
NpuTrainJob int `xorm:"NOT NULL DEFAULT 0"`
NpuInferenceJob int `xorm:"NOT NULL DEFAULT 0"`
GpuBenchMarkJob int `xorm:"NOT NULL DEFAULT 0"`
CloudBrainRunTime int `xorm:"NOT NULL DEFAULT 0"`
CommitDatasetNum int `xorm:"NOT NULL DEFAULT 0"`
UserIndex float64 `xorm:"NOT NULL DEFAULT 0"`
UserLocation string `xorm:"NULL"`
} }


type UserBusinessAnalysis struct { type UserBusinessAnalysis struct {
@@ -146,6 +158,18 @@ type UserBusinessAnalysis struct {
Name string `xorm:"NOT NULL"` Name string `xorm:"NOT NULL"`


DataDate string `xorm:"NULL"` DataDate string `xorm:"NULL"`

CloudBrainTaskNum int `xorm:"NOT NULL DEFAULT 0"`
GpuDebugJob int `xorm:"NOT NULL DEFAULT 0"`
NpuDebugJob int `xorm:"NOT NULL DEFAULT 0"`
GpuTrainJob int `xorm:"NOT NULL DEFAULT 0"`
NpuTrainJob int `xorm:"NOT NULL DEFAULT 0"`
NpuInferenceJob int `xorm:"NOT NULL DEFAULT 0"`
GpuBenchMarkJob int `xorm:"NOT NULL DEFAULT 0"`
CloudBrainRunTime int `xorm:"NOT NULL DEFAULT 0"`
CommitDatasetNum int `xorm:"NOT NULL DEFAULT 0"`
UserIndex float64 `xorm:"NOT NULL DEFAULT 0"`
UserLocation string `xorm:"NULL"`
} }


type UserBusinessAnalysisQueryOptions struct { type UserBusinessAnalysisQueryOptions struct {
@@ -183,6 +207,29 @@ func getLastCountDate() int64 {
return pageStartTime.Unix() return pageStartTime.Unix()
} }


func QueryMetrics(start int64, end int64) ([]*UserMetrics, int64) {
statictisSess := xStatistic.NewSession()
defer statictisSess.Close()
userMetricsList := make([]*UserMetrics, 0)
if err := statictisSess.Table(new(UserMetrics)).Where("count_date >" + fmt.Sprint(start) + " and count_date<" + fmt.Sprint(end)).OrderBy("count_date desc").
Find(&userMetricsList); err != nil {
return nil, 0
}
return userMetricsList, int64(len(userMetricsList))
}

func QueryRankList(key string, tableName string, limit int) ([]*UserBusinessAnalysisAll, int64) {
statictisSess := xStatistic.NewSession()
defer statictisSess.Close()

userBusinessAnalysisAllList := make([]*UserBusinessAnalysisAll, 0)
if err := statictisSess.Table(tableName).OrderBy(key+" desc,id desc").Limit(limit, 0).
Find(&userBusinessAnalysisAllList); err != nil {
return nil, 0
}
return userBusinessAnalysisAllList, int64(len(userBusinessAnalysisAllList))
}

func QueryUserStaticDataByTableName(start int, pageSize int, tableName string, queryObj interface{}, userName string) ([]*UserBusinessAnalysisAll, int64) { func QueryUserStaticDataByTableName(start int, pageSize int, tableName string, queryObj interface{}, userName string) ([]*UserBusinessAnalysisAll, int64) {
statictisSess := xStatistic.NewSession() statictisSess := xStatistic.NewSession()
defer statictisSess.Close() defer statictisSess.Close()
@@ -334,6 +381,7 @@ func QueryUserStaticDataPage(opts *UserBusinessAnalysisQueryOptions) ([]*UserBus
resultMap[userRecord.ID].WatchedCount += userRecord.WatchedCount resultMap[userRecord.ID].WatchedCount += userRecord.WatchedCount
resultMap[userRecord.ID].CommitCodeSize += userRecord.CommitCodeSize resultMap[userRecord.ID].CommitCodeSize += userRecord.CommitCodeSize
resultMap[userRecord.ID].CommitDatasetSize += userRecord.CommitDatasetSize resultMap[userRecord.ID].CommitDatasetSize += userRecord.CommitDatasetSize
resultMap[userRecord.ID].CommitDatasetNum += userRecord.CommitDatasetNum
resultMap[userRecord.ID].CommitModelCount += userRecord.CommitModelCount resultMap[userRecord.ID].CommitModelCount += userRecord.CommitModelCount
resultMap[userRecord.ID].SolveIssueCount += userRecord.SolveIssueCount resultMap[userRecord.ID].SolveIssueCount += userRecord.SolveIssueCount
resultMap[userRecord.ID].EncyclopediasCount += userRecord.EncyclopediasCount resultMap[userRecord.ID].EncyclopediasCount += userRecord.EncyclopediasCount
@@ -353,7 +401,7 @@ func QueryUserStaticDataPage(opts *UserBusinessAnalysisQueryOptions) ([]*UserBus
return userBusinessAnalysisReturnList, count return userBusinessAnalysisReturnList, count
} }


func refreshUserStaticTable(wikiCountMap map[string]int, CommitCodeSizeMap map[string]*git.UserKPIStats, tableName string, pageStartTime time.Time, pageEndTime time.Time) {
func refreshUserStaticTable(wikiCountMap map[string]int, tableName string, pageStartTime time.Time, pageEndTime time.Time, userMetrics map[string]int) {
sess := x.NewSession() sess := x.NewSession()
defer sess.Close() defer sess.Close()


@@ -379,14 +427,15 @@ func refreshUserStaticTable(wikiCountMap map[string]int, CommitCodeSizeMap map[s
FocusRepoCountMap := queryWatch(start_unix, end_unix) FocusRepoCountMap := queryWatch(start_unix, end_unix)
StarRepoCountMap := queryStar(start_unix, end_unix) StarRepoCountMap := queryStar(start_unix, end_unix)
WatchedCountMap := queryFollow(start_unix, end_unix) WatchedCountMap := queryFollow(start_unix, end_unix)
CommitDatasetSizeMap := queryDatasetSize(start_unix, end_unix)
CommitCodeSizeMap := queryCommitCodeSize(start_unix, end_unix)
CommitDatasetSizeMap, CommitDatasetNumMap := queryDatasetSize(start_unix, end_unix)
SolveIssueCountMap := querySolveIssue(start_unix, end_unix) SolveIssueCountMap := querySolveIssue(start_unix, end_unix)
CreateRepoCountMap := queryUserCreateRepo(start_unix, end_unix) CreateRepoCountMap := queryUserCreateRepo(start_unix, end_unix)
LoginCountMap := queryLoginCount(start_unix, end_unix) LoginCountMap := queryLoginCount(start_unix, end_unix)


OpenIIndexMap := queryUserRepoOpenIIndex(startTime.Unix(), end_unix) OpenIIndexMap := queryUserRepoOpenIIndex(startTime.Unix(), end_unix)

CloudBrainTaskMap, CloudBrainTaskItemMap := queryCloudBrainTask(start_unix, end_unix)
AiModelManageMap := queryUserModel(start_unix, end_unix)
DataDate := currentTimeNow.Format("2006-01-02") + " 00:01" DataDate := currentTimeNow.Format("2006-01-02") + " 00:01"


cond := "type != 1 and is_active=true" cond := "type != 1 and is_active=true"
@@ -395,6 +444,7 @@ func refreshUserStaticTable(wikiCountMap map[string]int, CommitCodeSizeMap map[s
log.Info("query user error. return.") log.Info("query user error. return.")
return return
} }
ParaWeight := getParaWeight()
var indexTotal int64 var indexTotal int64
indexTotal = 0 indexTotal = 0
insertCount := 0 insertCount := 0
@@ -412,84 +462,22 @@ func refreshUserStaticTable(wikiCountMap map[string]int, CommitCodeSizeMap map[s
dateRecordAll.Name = userRecord.Name dateRecordAll.Name = userRecord.Name
dateRecordAll.GiteaAgeMonth = subMonth(currentTimeNow, userRecord.CreatedUnix.AsTime()) dateRecordAll.GiteaAgeMonth = subMonth(currentTimeNow, userRecord.CreatedUnix.AsTime())
dateRecordAll.DataDate = DataDate dateRecordAll.DataDate = DataDate

if _, ok := CodeMergeCountMap[dateRecordAll.ID]; !ok {
dateRecordAll.CodeMergeCount = 0
} else {
dateRecordAll.CodeMergeCount = CodeMergeCountMap[dateRecordAll.ID]
}

if _, ok := CommitCountMap[dateRecordAll.ID]; !ok {
dateRecordAll.CommitCount = 0
} else {
dateRecordAll.CommitCount = CommitCountMap[dateRecordAll.ID]
}

if _, ok := IssueCountMap[dateRecordAll.ID]; !ok {
dateRecordAll.IssueCount = 0
} else {
dateRecordAll.IssueCount = IssueCountMap[dateRecordAll.ID]
}

if _, ok := CommentCountMap[dateRecordAll.ID]; !ok {
dateRecordAll.CommentCount = 0
} else {
dateRecordAll.CommentCount = CommentCountMap[dateRecordAll.ID]
}

if _, ok := FocusRepoCountMap[dateRecordAll.ID]; !ok {
dateRecordAll.FocusRepoCount = 0
} else {
dateRecordAll.FocusRepoCount = FocusRepoCountMap[dateRecordAll.ID]
}

if _, ok := StarRepoCountMap[dateRecordAll.ID]; !ok {
dateRecordAll.StarRepoCount = 0
} else {
dateRecordAll.StarRepoCount = StarRepoCountMap[dateRecordAll.ID]
}

if _, ok := WatchedCountMap[dateRecordAll.ID]; !ok {
dateRecordAll.WatchedCount = 0
} else {
dateRecordAll.WatchedCount = WatchedCountMap[dateRecordAll.ID]
}

if _, ok := CommitCodeSizeMap[dateRecordAll.Email]; !ok {
dateRecordAll.CommitCodeSize = 0
} else {
dateRecordAll.CommitCodeSize = int(CommitCodeSizeMap[dateRecordAll.Email].CommitLines)
}

if _, ok := CommitDatasetSizeMap[dateRecordAll.ID]; !ok {
dateRecordAll.CommitDatasetSize = 0
} else {
dateRecordAll.CommitDatasetSize = CommitDatasetSizeMap[dateRecordAll.ID]
}

if _, ok := SolveIssueCountMap[dateRecordAll.ID]; !ok {
dateRecordAll.SolveIssueCount = 0
} else {
dateRecordAll.SolveIssueCount = SolveIssueCountMap[dateRecordAll.ID]
}

if _, ok := wikiCountMap[dateRecordAll.Name]; !ok {
dateRecordAll.EncyclopediasCount = 0
} else {
dateRecordAll.EncyclopediasCount = wikiCountMap[dateRecordAll.Name]
}

if _, ok := CreateRepoCountMap[dateRecordAll.ID]; !ok {
dateRecordAll.CreateRepoCount = 0
} else {
dateRecordAll.CreateRepoCount = CreateRepoCountMap[dateRecordAll.ID]
}

if _, ok := LoginCountMap[dateRecordAll.ID]; !ok {
dateRecordAll.LoginCount = 0
} else {
dateRecordAll.LoginCount = LoginCountMap[dateRecordAll.ID]
}
dateRecordAll.UserLocation = userRecord.Location

dateRecordAll.CodeMergeCount = getMapValue(dateRecordAll.ID, CodeMergeCountMap)
dateRecordAll.CommitCount = getMapValue(dateRecordAll.ID, CommitCountMap)
dateRecordAll.IssueCount = getMapValue(dateRecordAll.ID, IssueCountMap)
dateRecordAll.CommentCount = getMapValue(dateRecordAll.ID, CommentCountMap)
dateRecordAll.FocusRepoCount = getMapValue(dateRecordAll.ID, FocusRepoCountMap)
dateRecordAll.StarRepoCount = getMapValue(dateRecordAll.ID, StarRepoCountMap)
dateRecordAll.WatchedCount = getMapValue(dateRecordAll.ID, WatchedCountMap)
dateRecordAll.CommitCodeSize = getMapValue(dateRecordAll.ID, CommitCodeSizeMap)
dateRecordAll.CommitDatasetSize = getMapValue(dateRecordAll.ID, CommitDatasetSizeMap)
dateRecordAll.CommitDatasetNum = getMapValue(dateRecordAll.ID, CommitDatasetNumMap)
dateRecordAll.SolveIssueCount = getMapValue(dateRecordAll.ID, SolveIssueCountMap)
dateRecordAll.EncyclopediasCount = getMapKeyStringValue(dateRecordAll.Name, wikiCountMap)
dateRecordAll.CreateRepoCount = getMapValue(dateRecordAll.ID, CreateRepoCountMap)
dateRecordAll.LoginCount = getMapValue(dateRecordAll.ID, LoginCountMap)


if _, ok := OpenIIndexMap[dateRecordAll.ID]; !ok { if _, ok := OpenIIndexMap[dateRecordAll.ID]; !ok {
dateRecordAll.OpenIIndex = 0 dateRecordAll.OpenIIndex = 0
@@ -497,7 +485,15 @@ func refreshUserStaticTable(wikiCountMap map[string]int, CommitCodeSizeMap map[s
dateRecordAll.OpenIIndex = OpenIIndexMap[dateRecordAll.ID] dateRecordAll.OpenIIndex = OpenIIndexMap[dateRecordAll.ID]
} }


dateRecordAll.CommitModelCount = 0
dateRecordAll.CloudBrainTaskNum = getMapValue(dateRecordAll.ID, CloudBrainTaskMap)
dateRecordAll.GpuDebugJob = getMapKeyStringValue(fmt.Sprint(dateRecordAll.ID)+"_GpuDebugJob", CloudBrainTaskItemMap)
dateRecordAll.NpuDebugJob = getMapKeyStringValue(fmt.Sprint(dateRecordAll.ID)+"_NpuDebugJob", CloudBrainTaskItemMap)
dateRecordAll.GpuTrainJob = getMapKeyStringValue(fmt.Sprint(dateRecordAll.ID)+"_GpuTrainJob", CloudBrainTaskItemMap)
dateRecordAll.NpuTrainJob = getMapKeyStringValue(fmt.Sprint(dateRecordAll.ID)+"_NpuTrainJob", CloudBrainTaskItemMap)
dateRecordAll.NpuInferenceJob = getMapKeyStringValue(fmt.Sprint(dateRecordAll.ID)+"_NpuInferenceJob", CloudBrainTaskItemMap)
dateRecordAll.GpuBenchMarkJob = getMapKeyStringValue(fmt.Sprint(dateRecordAll.ID)+"_GpuBenchMarkJob", CloudBrainTaskItemMap)
dateRecordAll.CommitModelCount = getMapValue(dateRecordAll.ID, AiModelManageMap)
dateRecordAll.UserIndex = getUserIndexFromAnalysisAll(dateRecordAll, ParaWeight)


dateRecordBatch = append(dateRecordBatch, dateRecordAll) dateRecordBatch = append(dateRecordBatch, dateRecordAll)
if len(dateRecordBatch) >= BATCH_INSERT_SIZE { if len(dateRecordBatch) >= BATCH_INSERT_SIZE {
@@ -508,6 +504,11 @@ func refreshUserStaticTable(wikiCountMap map[string]int, CommitCodeSizeMap map[s
} }
dateRecordBatch = make([]UserBusinessAnalysisAll, 0) dateRecordBatch = make([]UserBusinessAnalysisAll, 0)
} }
if tableName == "user_business_analysis_all" {
if dateRecordAll.UserIndex > 0 || dateRecordAll.LoginCount > 0 {
userMetrics["TotalHasActivityUser"] = getMapKeyStringValue("TotalHasActivityUser", userMetrics) + 1
}
}
} }
indexTotal += PAGE_SIZE indexTotal += PAGE_SIZE
if indexTotal >= count { if indexTotal >= count {
@@ -529,7 +530,7 @@ func insertTable(dateRecords []UserBusinessAnalysisAll, tableName string, static


insertBatchSql := "INSERT INTO public." + tableName + insertBatchSql := "INSERT INTO public." + tableName +
"(id, count_date, code_merge_count, commit_count, issue_count, comment_count, focus_repo_count, star_repo_count, watched_count, gitea_age_month, commit_code_size, commit_dataset_size, " + "(id, count_date, code_merge_count, commit_count, issue_count, comment_count, focus_repo_count, star_repo_count, watched_count, gitea_age_month, commit_code_size, commit_dataset_size, " +
"commit_model_count, solve_issue_count, encyclopedias_count, regist_date, create_repo_count, login_count, open_i_index, email, name, data_date) " +
"commit_model_count, solve_issue_count, encyclopedias_count, regist_date, create_repo_count, login_count, open_i_index, email, name, data_date,cloud_brain_task_num,gpu_debug_job,npu_debug_job,gpu_train_job,npu_train_job,npu_inference_job,gpu_bench_mark_job,cloud_brain_run_time,commit_dataset_num,user_index,user_location) " +
"VALUES" "VALUES"


for i, record := range dateRecords { for i, record := range dateRecords {
@@ -537,7 +538,7 @@ func insertTable(dateRecords []UserBusinessAnalysisAll, tableName string, static
", " + fmt.Sprint(record.IssueCount) + ", " + fmt.Sprint(record.CommentCount) + ", " + fmt.Sprint(record.FocusRepoCount) + ", " + fmt.Sprint(record.StarRepoCount) + ", " + fmt.Sprint(record.IssueCount) + ", " + fmt.Sprint(record.CommentCount) + ", " + fmt.Sprint(record.FocusRepoCount) + ", " + fmt.Sprint(record.StarRepoCount) +
", " + fmt.Sprint(record.WatchedCount) + ", " + fmt.Sprint(record.GiteaAgeMonth) + ", " + fmt.Sprint(record.CommitCodeSize) + ", " + fmt.Sprint(record.CommitDatasetSize) + ", " + fmt.Sprint(record.WatchedCount) + ", " + fmt.Sprint(record.GiteaAgeMonth) + ", " + fmt.Sprint(record.CommitCodeSize) + ", " + fmt.Sprint(record.CommitDatasetSize) +
", " + fmt.Sprint(record.CommitModelCount) + ", " + fmt.Sprint(record.SolveIssueCount) + ", " + fmt.Sprint(record.EncyclopediasCount) + ", " + fmt.Sprint(record.RegistDate) + ", " + fmt.Sprint(record.CommitModelCount) + ", " + fmt.Sprint(record.SolveIssueCount) + ", " + fmt.Sprint(record.EncyclopediasCount) + ", " + fmt.Sprint(record.RegistDate) +
", " + fmt.Sprint(record.CreateRepoCount) + ", " + fmt.Sprint(record.LoginCount) + ", " + fmt.Sprint(record.OpenIIndex) + ", '" + record.Email + "', '" + record.Name + "', '" + record.DataDate + "')"
", " + fmt.Sprint(record.CreateRepoCount) + ", " + fmt.Sprint(record.LoginCount) + ", " + fmt.Sprint(record.OpenIIndex) + ", '" + record.Email + "', '" + record.Name + "', '" + record.DataDate + "'," + fmt.Sprint(record.CloudBrainTaskNum) + "," + fmt.Sprint(record.GpuDebugJob) + "," + fmt.Sprint(record.NpuDebugJob) + "," + fmt.Sprint(record.GpuTrainJob) + "," + fmt.Sprint(record.NpuTrainJob) + "," + fmt.Sprint(record.NpuInferenceJob) + "," + fmt.Sprint(record.GpuBenchMarkJob) + "," + fmt.Sprint(record.CloudBrainRunTime) + "," + fmt.Sprint(record.CommitDatasetNum) + "," + fmt.Sprint(record.UserIndex) + ",'" + record.UserLocation + "')"
if i < (len(dateRecords) - 1) { if i < (len(dateRecords) - 1) {
insertBatchSql += "," insertBatchSql += ","
} }
@@ -546,36 +547,36 @@ func insertTable(dateRecords []UserBusinessAnalysisAll, tableName string, static
statictisSess.Exec(insertBatchSql) statictisSess.Exec(insertBatchSql)
} }


func RefreshUserStaticAllTabel(wikiCountMap map[string]int, CommitCodeSizeMap map[string]*git.UserKPIStats) {
func RefreshUserStaticAllTabel(wikiCountMap map[string]int, userMetrics map[string]int) {
currentTimeNow := time.Now() currentTimeNow := time.Now()
pageStartTime := time.Date(2021, 11, 5, 0, 0, 0, 0, currentTimeNow.Location()) pageStartTime := time.Date(2021, 11, 5, 0, 0, 0, 0, currentTimeNow.Location())
pageEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 23, 59, 59, 0, currentTimeNow.Location()) pageEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 23, 59, 59, 0, currentTimeNow.Location())
refreshUserStaticTable(wikiCountMap, CommitCodeSizeMap, "user_business_analysis_all", pageStartTime, pageEndTime)
refreshUserStaticTable(wikiCountMap, "user_business_analysis_all", pageStartTime, pageEndTime, userMetrics)
log.Info("refresh all data finished.") log.Info("refresh all data finished.")


pageStartTime = time.Date(currentTimeNow.Year(), 1, 1, 0, 0, 0, 0, currentTimeNow.Location()) pageStartTime = time.Date(currentTimeNow.Year(), 1, 1, 0, 0, 0, 0, currentTimeNow.Location())
refreshUserStaticTable(wikiCountMap, CommitCodeSizeMap, "user_business_analysis_current_year", pageStartTime, pageEndTime)
refreshUserStaticTable(wikiCountMap, "user_business_analysis_current_year", pageStartTime, pageEndTime, userMetrics)


thisMonth := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), 1, 0, 0, 0, 0, currentTimeNow.Location()) thisMonth := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), 1, 0, 0, 0, 0, currentTimeNow.Location())
refreshUserStaticTable(wikiCountMap, CommitCodeSizeMap, "user_business_analysis_current_month", thisMonth, pageEndTime)
refreshUserStaticTable(wikiCountMap, "user_business_analysis_current_month", thisMonth, pageEndTime, userMetrics)


offset := int(time.Monday - currentTimeNow.Weekday()) offset := int(time.Monday - currentTimeNow.Weekday())
if offset > 0 { if offset > 0 {
offset = -6 offset = -6
} }
pageStartTime = time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 0, 0, 0, 0, time.Local).AddDate(0, 0, offset) pageStartTime = time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 0, 0, 0, 0, time.Local).AddDate(0, 0, offset)
refreshUserStaticTable(wikiCountMap, CommitCodeSizeMap, "user_business_analysis_current_week", pageStartTime, pageEndTime)
refreshUserStaticTable(wikiCountMap, "user_business_analysis_current_week", pageStartTime, pageEndTime, userMetrics)


pageStartTime = time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 0, 0, 0, 0, time.Local).AddDate(0, 0, -30) pageStartTime = time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 0, 0, 0, 0, time.Local).AddDate(0, 0, -30)
refreshUserStaticTable(wikiCountMap, CommitCodeSizeMap, "user_business_analysis_last30_day", pageStartTime, pageEndTime)
refreshUserStaticTable(wikiCountMap, "user_business_analysis_last30_day", pageStartTime, pageEndTime, userMetrics)


pageStartTime = time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 0, 0, 0, 0, time.Local).AddDate(0, 0, -1) pageStartTime = time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 0, 0, 0, 0, time.Local).AddDate(0, 0, -1)
pageEndTime = time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 23, 59, 59, 0, currentTimeNow.Location()).AddDate(0, 0, -1) pageEndTime = time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 23, 59, 59, 0, currentTimeNow.Location()).AddDate(0, 0, -1)
refreshUserStaticTable(wikiCountMap, CommitCodeSizeMap, "user_business_analysis_yesterday", pageStartTime, pageEndTime)
refreshUserStaticTable(wikiCountMap, "user_business_analysis_yesterday", pageStartTime, pageEndTime, userMetrics)


pageStartTime = thisMonth.AddDate(0, -1, 0) pageStartTime = thisMonth.AddDate(0, -1, 0)
pageEndTime = time.Date(currentTimeNow.Year(), currentTimeNow.Month(), 1, 23, 59, 59, 0, currentTimeNow.Location()).AddDate(0, 0, -1) pageEndTime = time.Date(currentTimeNow.Year(), currentTimeNow.Month(), 1, 23, 59, 59, 0, currentTimeNow.Location()).AddDate(0, 0, -1)
refreshUserStaticTable(wikiCountMap, CommitCodeSizeMap, "user_business_analysis_last_month", pageStartTime, pageEndTime)
refreshUserStaticTable(wikiCountMap, "user_business_analysis_last_month", pageStartTime, pageEndTime, userMetrics)


} }


@@ -613,12 +614,13 @@ func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time,
} else { } else {
log.Info("query commit code size, len=" + fmt.Sprint(len(CommitCodeSizeMap))) log.Info("query commit code size, len=" + fmt.Sprint(len(CommitCodeSizeMap)))
} }
CommitDatasetSizeMap := queryDatasetSize(start_unix, end_unix)
CommitDatasetSizeMap, CommitDatasetNumMap := queryDatasetSize(start_unix, end_unix)
SolveIssueCountMap := querySolveIssue(start_unix, end_unix) SolveIssueCountMap := querySolveIssue(start_unix, end_unix)
CreateRepoCountMap := queryUserCreateRepo(start_unix, end_unix) CreateRepoCountMap := queryUserCreateRepo(start_unix, end_unix)
LoginCountMap := queryLoginCount(start_unix, end_unix) LoginCountMap := queryLoginCount(start_unix, end_unix)
OpenIIndexMap := queryUserRepoOpenIIndex(start_unix, end_unix) OpenIIndexMap := queryUserRepoOpenIIndex(start_unix, end_unix)

CloudBrainTaskMap, CloudBrainTaskItemMap := queryCloudBrainTask(start_unix, end_unix)
AiModelManageMap := queryUserModel(start_unix, end_unix)
statictisSess := xStatistic.NewSession() statictisSess := xStatistic.NewSession()
defer statictisSess.Close() defer statictisSess.Close()


@@ -628,6 +630,9 @@ func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time,
log.Info("query user error. return.") log.Info("query user error. return.")
return err return err
} }

ParaWeight := getParaWeight()
userMetrics := make(map[string]int)
var indexTotal int64 var indexTotal int64
indexTotal = 0 indexTotal = 0
for { for {
@@ -648,47 +653,14 @@ func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time,
dateRecord.Name = userRecord.Name dateRecord.Name = userRecord.Name
dateRecord.GiteaAgeMonth = subMonth(currentTimeNow, userRecord.CreatedUnix.AsTime()) dateRecord.GiteaAgeMonth = subMonth(currentTimeNow, userRecord.CreatedUnix.AsTime())
dateRecord.DataDate = DataDate dateRecord.DataDate = DataDate
if _, ok := CodeMergeCountMap[dateRecord.ID]; !ok {
dateRecord.CodeMergeCount = 0
} else {
dateRecord.CodeMergeCount = CodeMergeCountMap[dateRecord.ID]
}

if _, ok := CommitCountMap[dateRecord.ID]; !ok {
dateRecord.CommitCount = 0
} else {
dateRecord.CommitCount = CommitCountMap[dateRecord.ID]
}

if _, ok := IssueCountMap[dateRecord.ID]; !ok {
dateRecord.IssueCount = 0
} else {
dateRecord.IssueCount = IssueCountMap[dateRecord.ID]
}

if _, ok := CommentCountMap[dateRecord.ID]; !ok {
dateRecord.CommentCount = 0
} else {
dateRecord.CommentCount = CommentCountMap[dateRecord.ID]
}

if _, ok := FocusRepoCountMap[dateRecord.ID]; !ok {
dateRecord.FocusRepoCount = 0
} else {
dateRecord.FocusRepoCount = FocusRepoCountMap[dateRecord.ID]
}


if _, ok := StarRepoCountMap[dateRecord.ID]; !ok {
dateRecord.StarRepoCount = 0
} else {
dateRecord.StarRepoCount = StarRepoCountMap[dateRecord.ID]
}

if _, ok := WatchedCountMap[dateRecord.ID]; !ok {
dateRecord.WatchedCount = 0
} else {
dateRecord.WatchedCount = WatchedCountMap[dateRecord.ID]
}
dateRecord.CodeMergeCount = getMapValue(dateRecord.ID, CodeMergeCountMap)
dateRecord.CommitCount = getMapValue(dateRecord.ID, CommitCountMap)
dateRecord.IssueCount = getMapValue(dateRecord.ID, IssueCountMap)
dateRecord.CommentCount = getMapValue(dateRecord.ID, CommentCountMap)
dateRecord.FocusRepoCount = getMapValue(dateRecord.ID, FocusRepoCountMap)
dateRecord.StarRepoCount = getMapValue(dateRecord.ID, StarRepoCountMap)
dateRecord.WatchedCount = getMapValue(dateRecord.ID, WatchedCountMap)


if _, ok := CommitCodeSizeMap[dateRecord.Email]; !ok { if _, ok := CommitCodeSizeMap[dateRecord.Email]; !ok {
dateRecord.CommitCodeSize = 0 dateRecord.CommitCodeSize = 0
@@ -696,35 +668,15 @@ func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time,
dateRecord.CommitCodeSize = int(CommitCodeSizeMap[dateRecord.Email].CommitLines) dateRecord.CommitCodeSize = int(CommitCodeSizeMap[dateRecord.Email].CommitLines)
} }


if _, ok := CommitDatasetSizeMap[dateRecord.ID]; !ok {
dateRecord.CommitDatasetSize = 0
} else {
dateRecord.CommitDatasetSize = CommitDatasetSizeMap[dateRecord.ID]
}
dateRecord.CommitDatasetSize = getMapValue(dateRecord.ID, CommitDatasetSizeMap)
dateRecord.CommitDatasetNum = getMapValue(dateRecord.ID, CommitDatasetNumMap)
dateRecord.SolveIssueCount = getMapValue(dateRecord.ID, SolveIssueCountMap)


if _, ok := SolveIssueCountMap[dateRecord.ID]; !ok {
dateRecord.SolveIssueCount = 0
} else {
dateRecord.SolveIssueCount = SolveIssueCountMap[dateRecord.ID]
}
dateRecord.EncyclopediasCount = getMapKeyStringValue(dateRecord.Name, wikiCountMap)


if _, ok := wikiCountMap[dateRecord.Name]; !ok {
dateRecord.EncyclopediasCount = 0
} else {
dateRecord.EncyclopediasCount = wikiCountMap[dateRecord.Name]
}
dateRecord.CreateRepoCount = getMapValue(dateRecord.ID, CreateRepoCountMap)


if _, ok := CreateRepoCountMap[dateRecord.ID]; !ok {
dateRecord.CreateRepoCount = 0
} else {
dateRecord.CreateRepoCount = CreateRepoCountMap[dateRecord.ID]
}

if _, ok := LoginCountMap[dateRecord.ID]; !ok {
dateRecord.LoginCount = 0
} else {
dateRecord.LoginCount = LoginCountMap[dateRecord.ID]
}
dateRecord.LoginCount = getMapValue(dateRecord.ID, LoginCountMap)


if _, ok := OpenIIndexMap[dateRecord.ID]; !ok { if _, ok := OpenIIndexMap[dateRecord.ID]; !ok {
dateRecord.OpenIIndex = 0 dateRecord.OpenIIndex = 0
@@ -732,8 +684,17 @@ func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time,
dateRecord.OpenIIndex = OpenIIndexMap[dateRecord.ID] dateRecord.OpenIIndex = OpenIIndexMap[dateRecord.ID]
} }


dateRecord.CommitModelCount = 0

dateRecord.CloudBrainTaskNum = getMapValue(dateRecord.ID, CloudBrainTaskMap)
dateRecord.GpuDebugJob = getMapKeyStringValue(fmt.Sprint(dateRecord.ID)+"_GpuDebugJob", CloudBrainTaskItemMap)
dateRecord.NpuDebugJob = getMapKeyStringValue(fmt.Sprint(dateRecord.ID)+"_NpuDebugJob", CloudBrainTaskItemMap)
dateRecord.GpuTrainJob = getMapKeyStringValue(fmt.Sprint(dateRecord.ID)+"_GpuTrainJob", CloudBrainTaskItemMap)
dateRecord.NpuTrainJob = getMapKeyStringValue(fmt.Sprint(dateRecord.ID)+"_NpuTrainJob", CloudBrainTaskItemMap)
dateRecord.NpuInferenceJob = getMapKeyStringValue(fmt.Sprint(dateRecord.ID)+"_NpuInferenceJob", CloudBrainTaskItemMap)
dateRecord.GpuBenchMarkJob = getMapKeyStringValue(fmt.Sprint(dateRecord.ID)+"_GpuBenchMarkJob", CloudBrainTaskItemMap)
dateRecord.CloudBrainRunTime = getMapKeyStringValue(fmt.Sprint(dateRecord.ID)+"_CloudBrainRunTime", CloudBrainTaskItemMap)
dateRecord.CommitModelCount = getMapValue(dateRecord.ID, AiModelManageMap)
dateRecord.UserIndex = getUserIndex(dateRecord, ParaWeight)
setUserMetrics(userMetrics, userRecord, start_unix, end_unix, dateRecord)
_, err = statictisSess.Insert(&dateRecord) _, err = statictisSess.Insert(&dateRecord)
if err != nil { if err != nil {
log.Info("insert daterecord failed." + err.Error()) log.Info("insert daterecord failed." + err.Error())
@@ -747,11 +708,142 @@ func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time,
} }
} }


RefreshUserStaticAllTabel(wikiCountMap, CommitCodeSizeMap)
RefreshUserStaticAllTabel(wikiCountMap, userMetrics)

//insert userMetrics table
var useMetrics UserMetrics
useMetrics.CountDate = CountDate.Unix()
statictisSess.Delete(&useMetrics)

useMetrics.ActivateRegistUser = getMapKeyStringValue("ActivateRegistUser", userMetrics)
useMetrics.HasActivityUser = getMapKeyStringValue("HasActivityUser", userMetrics)
useMetrics.NotActivateRegistUser = getMapKeyStringValue("NotActivateRegistUser", userMetrics)
useMetrics.TotalActivateRegistUser = getMapKeyStringValue("TotalActivateRegistUser", userMetrics)
useMetrics.TotalHasActivityUser = getMapKeyStringValue("TotalHasActivityUser", userMetrics)
statictisSess.Insert(&useMetrics)


return nil return nil
} }


func setUserMetrics(userMetrics map[string]int, user *User, start_time int64, end_time int64, dateRecord UserBusinessAnalysis) {
//ActivateRegistUser int `xorm:"NOT NULL DEFAULT 0"`
//NotActivateRegistUser int `xorm:"NOT NULL DEFAULT 0"`
//HasActivityUser int `xorm:"NOT NULL DEFAULT 0"`
//TotalActivateRegistUser int `xorm:"NOT NULL DEFAULT 0"`
//TotalHasActivityUser
regist_time := user.CreatedUnix.AsTime().Unix()
if regist_time >= start_time && regist_time <= end_time {
if user.IsActive {
userMetrics["ActivateRegistUser"] = getMapKeyStringValue("ActivateRegistUser", userMetrics) + 1
} else {
userMetrics["NotActivateRegistUser"] = getMapKeyStringValue("NotActivateRegistUser", userMetrics) + 1
}
}
if user.IsActive {
userMetrics["TotalActivateRegistUser"] = getMapKeyStringValue("TotalActivateRegistUser", userMetrics) + 1
}

if dateRecord.UserIndex > 0 || dateRecord.LoginCount > 0 {
userMetrics["HasActivityUser"] = getMapKeyStringValue("HasActivityUser", userMetrics) + 1
}

}

func getParaWeight() map[string]float64 {
result := make(map[string]float64)
statictisSess := xStatistic.NewSession()
defer statictisSess.Close()
statictisSess.Select("*").Table(new(UserAnalysisPara))
paraList := make([]*UserAnalysisPara, 0)
statictisSess.Find(&paraList)
for _, paraRecord := range paraList {
result[paraRecord.Key] = paraRecord.Value
}
return result
}

func getUserIndexFromAnalysisAll(dateRecord UserBusinessAnalysisAll, ParaWeight map[string]float64) float64 {
var result float64
// PR数 0.20
// commit数 0.20
// 提出任务数 0.20
// 评论数 0.20
// 关注项目数 0.10
// 点赞项目数 0.10
// 登录次数 0.10
result = float64(dateRecord.CodeMergeCount) * getParaWeightValue("CodeMergeCount", ParaWeight, 0.2)
result += float64(dateRecord.CommitCount) * getParaWeightValue("CommitCount", ParaWeight, 0.2)
log.Info("1 result=" + fmt.Sprint(result))
result += float64(dateRecord.IssueCount) * getParaWeightValue("IssueCount", ParaWeight, 0.2)
result += float64(dateRecord.CommentCount) * getParaWeightValue("CommentCount", ParaWeight, 0.2)
result += float64(dateRecord.FocusRepoCount) * getParaWeightValue("FocusRepoCount", ParaWeight, 0.1)
result += float64(dateRecord.StarRepoCount) * getParaWeightValue("StarRepoCount", ParaWeight, 0.1)
result += float64(dateRecord.LoginCount) * getParaWeightValue("LoginCount", ParaWeight, 0.1)
result += float64(dateRecord.WatchedCount) * getParaWeightValue("WatchedCount", ParaWeight, 0.3)
result += float64(dateRecord.CommitCodeSize) * getParaWeightValue("CommitCodeSize", ParaWeight, 0.1)
result += float64(dateRecord.SolveIssueCount) * getParaWeightValue("SolveIssueCount", ParaWeight, 0.2)
result += float64(dateRecord.EncyclopediasCount) * getParaWeightValue("EncyclopediasCount", ParaWeight, 0.1)
result += float64(dateRecord.CreateRepoCount) * getParaWeightValue("CreateRepoCount", ParaWeight, 0.05)
result += float64(dateRecord.CloudBrainTaskNum) * getParaWeightValue("CloudBrainTaskNum", ParaWeight, 0.3)
result += float64(dateRecord.CommitModelCount) * getParaWeightValue("CommitModelCount", ParaWeight, 0.2)
result += dateRecord.OpenIIndex * getParaWeightValue("OpenIIndex", ParaWeight, 0.1)

return result
}

func getUserIndex(dateRecord UserBusinessAnalysis, ParaWeight map[string]float64) float64 {
var result float64
// PR数 0.20
// commit数 0.20
// 提出任务数 0.20
// 评论数 0.20
// 关注项目数 0.10
// 点赞项目数 0.10
// 登录次数 0.10
result = float64(dateRecord.CodeMergeCount) * getParaWeightValue("CodeMergeCount", ParaWeight, 0.2)
result += float64(dateRecord.CommitCount) * getParaWeightValue("CommitCount", ParaWeight, 0.2)
log.Info("2 result=" + fmt.Sprint(result))
result += float64(dateRecord.IssueCount) * getParaWeightValue("IssueCount", ParaWeight, 0.2)
result += float64(dateRecord.CommentCount) * getParaWeightValue("CommentCount", ParaWeight, 0.2)
result += float64(dateRecord.FocusRepoCount) * getParaWeightValue("FocusRepoCount", ParaWeight, 0.1)
result += float64(dateRecord.StarRepoCount) * getParaWeightValue("StarRepoCount", ParaWeight, 0.1)
result += float64(dateRecord.LoginCount) * getParaWeightValue("LoginCount", ParaWeight, 0.1)
result += float64(dateRecord.WatchedCount) * getParaWeightValue("WatchedCount", ParaWeight, 0.3)
result += float64(dateRecord.CommitCodeSize) * getParaWeightValue("CommitCodeSize", ParaWeight, 0.1)
result += float64(dateRecord.SolveIssueCount) * getParaWeightValue("SolveIssueCount", ParaWeight, 0.2)
result += float64(dateRecord.EncyclopediasCount) * getParaWeightValue("EncyclopediasCount", ParaWeight, 0.1)
result += float64(dateRecord.CreateRepoCount) * getParaWeightValue("CreateRepoCount", ParaWeight, 0.05)
result += float64(dateRecord.CloudBrainTaskNum) * getParaWeightValue("CloudBrainTaskNum", ParaWeight, 0.3)
result += float64(dateRecord.CommitModelCount) * getParaWeightValue("CommitModelCount", ParaWeight, 0.2)
result += dateRecord.OpenIIndex * getParaWeightValue("OpenIIndex", ParaWeight, 0.1)

return result
}

func getParaWeightValue(key string, valueMap map[string]float64, defaultValue float64) float64 {
if _, ok := valueMap[key]; !ok {
return defaultValue
} else {
return valueMap[key]
}
}

func getMapKeyStringValue(key string, valueMap map[string]int) int {
if _, ok := valueMap[key]; !ok {
return 0
} else {
return valueMap[key]
}
}

func getMapValue(userId int64, valueMap map[int64]int) int {
if _, ok := valueMap[userId]; !ok {
return 0
} else {
return valueMap[userId]
}
}

func getInt(str string) int { func getInt(str string) int {
re, err := strconv.ParseInt(str, 10, 32) re, err := strconv.ParseInt(str, 10, 32)
if err != nil { if err != nil {
@@ -1052,16 +1144,17 @@ func queryFollow(start_unix int64, end_unix int64) map[int64]int {
return resultMap return resultMap
} }


func queryDatasetSize(start_unix int64, end_unix int64) map[int64]int {
func queryDatasetSize(start_unix int64, end_unix int64) (map[int64]int, map[int64]int) {
sess := x.NewSession() sess := x.NewSession()
defer sess.Close() defer sess.Close()
resultMap := make(map[int64]int)
resultSizeMap := make(map[int64]int)
resultNumMap := make(map[int64]int)
cond := " created_unix>=" + fmt.Sprint(start_unix) + " and created_unix<=" + fmt.Sprint(end_unix) cond := " created_unix>=" + fmt.Sprint(start_unix) + " and created_unix<=" + fmt.Sprint(end_unix)


count, err := sess.Where(cond).Count(new(Attachment)) count, err := sess.Where(cond).Count(new(Attachment))
if err != nil { if err != nil {
log.Info("query attachment error. return.") log.Info("query attachment error. return.")
return resultMap
return resultSizeMap, resultNumMap
} }
var indexTotal int64 var indexTotal int64
indexTotal = 0 indexTotal = 0
@@ -1072,10 +1165,12 @@ func queryDatasetSize(start_unix int64, end_unix int64) map[int64]int {


log.Info("query Attachment size=" + fmt.Sprint(len(attachmentList))) log.Info("query Attachment size=" + fmt.Sprint(len(attachmentList)))
for _, attachRecord := range attachmentList { for _, attachRecord := range attachmentList {
if _, ok := resultMap[attachRecord.UploaderID]; !ok {
resultMap[attachRecord.UploaderID] = int(attachRecord.Size / (1024 * 1024)) //MB
if _, ok := resultSizeMap[attachRecord.UploaderID]; !ok {
resultSizeMap[attachRecord.UploaderID] = int(attachRecord.Size / (1024 * 1024)) //MB
resultNumMap[attachRecord.UploaderID] = 1
} else { } else {
resultMap[attachRecord.UploaderID] += int(attachRecord.Size / (1024 * 1024)) //MB
resultSizeMap[attachRecord.UploaderID] += int(attachRecord.Size / (1024 * 1024)) //MB
resultNumMap[attachRecord.UploaderID] += 1
} }
} }


@@ -1085,7 +1180,7 @@ func queryDatasetSize(start_unix int64, end_unix int64) map[int64]int {
} }
} }


return resultMap
return resultSizeMap, resultNumMap
} }


func queryUserCreateRepo(start_unix int64, end_unix int64) map[int64]int { func queryUserCreateRepo(start_unix int64, end_unix int64) map[int64]int {
@@ -1212,6 +1307,133 @@ func queryLoginCount(start_unix int64, end_unix int64) map[int64]int {
return resultMap return resultMap
} }


func queryCommitCodeSize(start_unix int64, end_unix int64) map[int64]int {
statictisSess := xStatistic.NewSession()
defer statictisSess.Close()

resultMap := make(map[int64]int)
cond := "count_date>=" + fmt.Sprint(start_unix) + " and count_date<=" + fmt.Sprint(end_unix)
count, err := statictisSess.Where(cond).Count(new(UserBusinessAnalysis))
if err != nil {
log.Info("query commit code size error. return.")
return resultMap
}
var indexTotal int64
indexTotal = 0
for {
statictisSess.Select("id,commit_code_size").Table("user_business_analysis").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal))
userBusinessAnalysisList := make([]*UserBusinessAnalysis, 0)
statictisSess.Find(&userBusinessAnalysisList)
log.Info("query user login size=" + fmt.Sprint(len(userBusinessAnalysisList)))
for _, analysisRecord := range userBusinessAnalysisList {
if _, ok := resultMap[analysisRecord.ID]; !ok {
resultMap[analysisRecord.ID] = analysisRecord.CommitCodeSize
} else {
resultMap[analysisRecord.ID] += analysisRecord.CommitCodeSize
}
}
indexTotal += PAGE_SIZE
if indexTotal >= count {
break
}
}
log.Info("user commit code size=" + fmt.Sprint(len(resultMap)))
return resultMap
}

func queryUserModel(start_unix int64, end_unix int64) map[int64]int {
sess := x.NewSession()
defer sess.Close()
resultMap := make(map[int64]int)
cond := " created_unix>=" + fmt.Sprint(start_unix) + " and created_unix<=" + fmt.Sprint(end_unix)
count, err := sess.Where(cond).Count(new(AiModelManage))
if err != nil {
log.Info("query AiModelManage error. return.")
return resultMap
}
var indexTotal int64
indexTotal = 0
for {
sess.Select("id,user_id").Table("ai_model_manage").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal))
aiModelList := make([]*AiModelManage, 0)
sess.Find(&aiModelList)
log.Info("query AiModelManage size=" + fmt.Sprint(len(aiModelList)))
for _, aiModelRecord := range aiModelList {
if _, ok := resultMap[aiModelRecord.UserId]; !ok {
resultMap[aiModelRecord.UserId] = 1
} else {
resultMap[aiModelRecord.UserId] += 1
}
}
indexTotal += PAGE_SIZE
if indexTotal >= count {
break
}
}
return resultMap
}

func queryCloudBrainTask(start_unix int64, end_unix int64) (map[int64]int, map[string]int) {
sess := x.NewSession()
defer sess.Close()
resultMap := make(map[int64]int)
resultItemMap := make(map[string]int)

cond := " created_unix>=" + fmt.Sprint(start_unix) + " and created_unix<=" + fmt.Sprint(end_unix)
count, err := sess.Where(cond).Count(new(Cloudbrain))
if err != nil {
log.Info("query cloudbrain error. return.")
return resultMap, resultItemMap
}
var indexTotal int64
indexTotal = 0
for {
sess.Select("id,job_type,user_id,duration,train_job_duration,type").Table("cloudbrain").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal))
cloudTaskList := make([]*Cloudbrain, 0)
sess.Find(&cloudTaskList)
log.Info("query cloudbrain size=" + fmt.Sprint(len(cloudTaskList)))
for _, cloudTaskRecord := range cloudTaskList {
if _, ok := resultMap[cloudTaskRecord.UserID]; !ok {
resultMap[cloudTaskRecord.UserID] = 1
} else {
resultMap[cloudTaskRecord.UserID] += 1
}
setMapKey("CloudBrainRunTime", cloudTaskRecord.UserID, int(cloudTaskRecord.Duration), resultItemMap)
if cloudTaskRecord.Type == 1 { //npu
if cloudTaskRecord.JobType == "TRAIN" {
setMapKey("NpuTrainJob", cloudTaskRecord.UserID, 1, resultItemMap)
} else if cloudTaskRecord.JobType == "INFERENCE" {
setMapKey("NpuInferenceJob", cloudTaskRecord.UserID, 1, resultItemMap)
} else {
setMapKey("NpuDebugJob", cloudTaskRecord.UserID, 1, resultItemMap)
}
} else { //type=0 gpu
if cloudTaskRecord.JobType == "TRAIN" {
setMapKey("GpuTrainJob", cloudTaskRecord.UserID, 1, resultItemMap)
} else if cloudTaskRecord.JobType == "BENCHMARK" {
setMapKey("GpuBenchMarkJob", cloudTaskRecord.UserID, 1, resultItemMap)
} else {
setMapKey("GpuDebugJob", cloudTaskRecord.UserID, 1, resultItemMap)
}
}
}
indexTotal += PAGE_SIZE
if indexTotal >= count {
break
}
}

return resultMap, resultItemMap
}
func setMapKey(key string, userId int64, value int, resultItemMap map[string]int) {
newKey := fmt.Sprint(userId) + "_" + key
if _, ok := resultItemMap[newKey]; !ok {
resultItemMap[newKey] = value
} else {
resultItemMap[newKey] += value
}
}

func subMonth(t1, t2 time.Time) (month int) { func subMonth(t1, t2 time.Time) (month int) {
y1 := t1.Year() y1 := t1.Year()
y2 := t2.Year() y2 := t2.Year()


+ 86
- 0
models/user_business_struct.go View File

@@ -44,6 +44,18 @@ type UserBusinessAnalysisCurrentYear struct {
//user //user
Name string `xorm:"NOT NULL"` Name string `xorm:"NOT NULL"`
DataDate string `xorm:"NULL"` DataDate string `xorm:"NULL"`

CloudBrainTaskNum int `xorm:"NOT NULL DEFAULT 0"`
GpuDebugJob int `xorm:"NOT NULL DEFAULT 0"`
NpuDebugJob int `xorm:"NOT NULL DEFAULT 0"`
GpuTrainJob int `xorm:"NOT NULL DEFAULT 0"`
NpuTrainJob int `xorm:"NOT NULL DEFAULT 0"`
NpuInferenceJob int `xorm:"NOT NULL DEFAULT 0"`
GpuBenchMarkJob int `xorm:"NOT NULL DEFAULT 0"`
CloudBrainRunTime int `xorm:"NOT NULL DEFAULT 0"`
CommitDatasetNum int `xorm:"NOT NULL DEFAULT 0"`
UserIndex float64 `xorm:"NOT NULL DEFAULT 0"`
UserLocation string `xorm:"NULL"`
} }


type UserBusinessAnalysisLast30Day struct { type UserBusinessAnalysisLast30Day struct {
@@ -88,6 +100,18 @@ type UserBusinessAnalysisLast30Day struct {
//user //user
Name string `xorm:"NOT NULL"` Name string `xorm:"NOT NULL"`
DataDate string `xorm:"NULL"` DataDate string `xorm:"NULL"`

CloudBrainTaskNum int `xorm:"NOT NULL DEFAULT 0"`
GpuDebugJob int `xorm:"NOT NULL DEFAULT 0"`
NpuDebugJob int `xorm:"NOT NULL DEFAULT 0"`
GpuTrainJob int `xorm:"NOT NULL DEFAULT 0"`
NpuTrainJob int `xorm:"NOT NULL DEFAULT 0"`
NpuInferenceJob int `xorm:"NOT NULL DEFAULT 0"`
GpuBenchMarkJob int `xorm:"NOT NULL DEFAULT 0"`
CloudBrainRunTime int `xorm:"NOT NULL DEFAULT 0"`
CommitDatasetNum int `xorm:"NOT NULL DEFAULT 0"`
UserIndex float64 `xorm:"NOT NULL DEFAULT 0"`
UserLocation string `xorm:"NULL"`
} }


type UserBusinessAnalysisLastMonth struct { type UserBusinessAnalysisLastMonth struct {
@@ -132,6 +156,18 @@ type UserBusinessAnalysisLastMonth struct {
//user //user
Name string `xorm:"NOT NULL"` Name string `xorm:"NOT NULL"`
DataDate string `xorm:"NULL"` DataDate string `xorm:"NULL"`

CloudBrainTaskNum int `xorm:"NOT NULL DEFAULT 0"`
GpuDebugJob int `xorm:"NOT NULL DEFAULT 0"`
NpuDebugJob int `xorm:"NOT NULL DEFAULT 0"`
GpuTrainJob int `xorm:"NOT NULL DEFAULT 0"`
NpuTrainJob int `xorm:"NOT NULL DEFAULT 0"`
NpuInferenceJob int `xorm:"NOT NULL DEFAULT 0"`
GpuBenchMarkJob int `xorm:"NOT NULL DEFAULT 0"`
CloudBrainRunTime int `xorm:"NOT NULL DEFAULT 0"`
CommitDatasetNum int `xorm:"NOT NULL DEFAULT 0"`
UserIndex float64 `xorm:"NOT NULL DEFAULT 0"`
UserLocation string `xorm:"NULL"`
} }


type UserBusinessAnalysisCurrentMonth struct { type UserBusinessAnalysisCurrentMonth struct {
@@ -176,6 +212,18 @@ type UserBusinessAnalysisCurrentMonth struct {
//user //user
Name string `xorm:"NOT NULL"` Name string `xorm:"NOT NULL"`
DataDate string `xorm:"NULL"` DataDate string `xorm:"NULL"`

CloudBrainTaskNum int `xorm:"NOT NULL DEFAULT 0"`
GpuDebugJob int `xorm:"NOT NULL DEFAULT 0"`
NpuDebugJob int `xorm:"NOT NULL DEFAULT 0"`
GpuTrainJob int `xorm:"NOT NULL DEFAULT 0"`
NpuTrainJob int `xorm:"NOT NULL DEFAULT 0"`
NpuInferenceJob int `xorm:"NOT NULL DEFAULT 0"`
GpuBenchMarkJob int `xorm:"NOT NULL DEFAULT 0"`
CloudBrainRunTime int `xorm:"NOT NULL DEFAULT 0"`
CommitDatasetNum int `xorm:"NOT NULL DEFAULT 0"`
UserIndex float64 `xorm:"NOT NULL DEFAULT 0"`
UserLocation string `xorm:"NULL"`
} }


type UserBusinessAnalysisCurrentWeek struct { type UserBusinessAnalysisCurrentWeek struct {
@@ -220,6 +268,18 @@ type UserBusinessAnalysisCurrentWeek struct {
//user //user
Name string `xorm:"NOT NULL"` Name string `xorm:"NOT NULL"`
DataDate string `xorm:"NULL"` DataDate string `xorm:"NULL"`

CloudBrainTaskNum int `xorm:"NOT NULL DEFAULT 0"`
GpuDebugJob int `xorm:"NOT NULL DEFAULT 0"`
NpuDebugJob int `xorm:"NOT NULL DEFAULT 0"`
GpuTrainJob int `xorm:"NOT NULL DEFAULT 0"`
NpuTrainJob int `xorm:"NOT NULL DEFAULT 0"`
NpuInferenceJob int `xorm:"NOT NULL DEFAULT 0"`
GpuBenchMarkJob int `xorm:"NOT NULL DEFAULT 0"`
CloudBrainRunTime int `xorm:"NOT NULL DEFAULT 0"`
CommitDatasetNum int `xorm:"NOT NULL DEFAULT 0"`
UserIndex float64 `xorm:"NOT NULL DEFAULT 0"`
UserLocation string `xorm:"NULL"`
} }


type UserBusinessAnalysisYesterday struct { type UserBusinessAnalysisYesterday struct {
@@ -264,4 +324,30 @@ type UserBusinessAnalysisYesterday struct {
//user //user
Name string `xorm:"NOT NULL"` Name string `xorm:"NOT NULL"`
DataDate string `xorm:"NULL"` DataDate string `xorm:"NULL"`

CloudBrainTaskNum int `xorm:"NOT NULL DEFAULT 0"`
GpuDebugJob int `xorm:"NOT NULL DEFAULT 0"`
NpuDebugJob int `xorm:"NOT NULL DEFAULT 0"`
GpuTrainJob int `xorm:"NOT NULL DEFAULT 0"`
NpuTrainJob int `xorm:"NOT NULL DEFAULT 0"`
NpuInferenceJob int `xorm:"NOT NULL DEFAULT 0"`
GpuBenchMarkJob int `xorm:"NOT NULL DEFAULT 0"`
CloudBrainRunTime int `xorm:"NOT NULL DEFAULT 0"`
CommitDatasetNum int `xorm:"NOT NULL DEFAULT 0"`
UserIndex float64 `xorm:"NOT NULL DEFAULT 0"`
UserLocation string `xorm:"NULL"`
}

type UserAnalysisPara struct {
Key string `xorm:"NOT NULL"`
Value float64 `xorm:"NOT NULL DEFAULT 0"`
}

type UserMetrics struct {
CountDate int64 `xorm:"pk"`
ActivateRegistUser int `xorm:"NOT NULL DEFAULT 0"`
NotActivateRegistUser int `xorm:"NOT NULL DEFAULT 0"`
HasActivityUser int `xorm:"NOT NULL DEFAULT 0"`
TotalActivateRegistUser int `xorm:"NOT NULL DEFAULT 0"`
TotalHasActivityUser int `xorm:"NOT NULL DEFAULT 0"`
} }

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

@@ -20,6 +20,9 @@ type CreateCloudBrainForm struct {
ResourceSpecId int `form:"resource_spec_id" binding:"Required"` ResourceSpecId int `form:"resource_spec_id" binding:"Required"`
BenchmarkTypeID int `form:"benchmark_types_id"` BenchmarkTypeID int `form:"benchmark_types_id"`
BenchmarkChildTypeID int `form:"benchmark_child_types_id"` BenchmarkChildTypeID int `form:"benchmark_child_types_id"`
BootFile string `form:"boot_file"`
Params string `form:"run_para_list"`
BranchName string `form:"branch_name"`
} }


type CommitImageCloudBrainForm struct { type CommitImageCloudBrainForm struct {


+ 49
- 14
modules/cloudbrain/cloudbrain.go View File

@@ -15,14 +15,13 @@ import (
) )


const ( const (
Command = `pip3 install jupyterlab==2.2.5 -i https://pypi.tuna.tsinghua.edu.cn/simple;
service ssh stop;
jupyter lab --no-browser --ip=0.0.0.0 --allow-root --notebook-dir="/code" --port=80 --LabApp.token="" --LabApp.allow_origin="self https://cloudbrain.pcl.ac.cn"`
Command = `pip3 install jupyterlab==2.2.5 -i https://pypi.tuna.tsinghua.edu.cn/simple;service ssh stop;jupyter lab --no-browser --ip=0.0.0.0 --allow-root --notebook-dir="/code" --port=80 --LabApp.token="" --LabApp.allow_origin="self https://cloudbrain.pcl.ac.cn"`
//CommandBenchmark = `echo "start benchmark";python /code/test.py;echo "end benchmark"` //CommandBenchmark = `echo "start benchmark";python /code/test.py;echo "end benchmark"`
CommandBenchmark = `echo "start benchmark";cd /benchmark && bash run_bk.sh;echo "end benchmark"` CommandBenchmark = `echo "start benchmark";cd /benchmark && bash run_bk.sh;echo "end benchmark"`
CodeMountPath = "/code" CodeMountPath = "/code"
DataSetMountPath = "/dataset" DataSetMountPath = "/dataset"
ModelMountPath = "/model" ModelMountPath = "/model"
LogFile = "log.txt"
BenchMarkMountPath = "/benchmark" BenchMarkMountPath = "/benchmark"
BenchMarkResourceID = 1 BenchMarkResourceID = 1
Snn4imagenetMountPath = "/snn4imagenet" Snn4imagenetMountPath = "/snn4imagenet"
@@ -32,10 +31,13 @@ const (
SubTaskName = "task1" SubTaskName = "task1"


Success = "S000" Success = "S000"

DefaultBranchName = "master"
) )


var ( var (
ResourceSpecs *models.ResourceSpecs
ResourceSpecs *models.ResourceSpecs
TrainResourceSpecs *models.ResourceSpecs
) )


func isAdminOrOwnerOrJobCreater(ctx *context.Context, job *models.Cloudbrain, err error) bool { func isAdminOrOwnerOrJobCreater(ctx *context.Context, job *models.Cloudbrain, err error) bool {
@@ -147,7 +149,7 @@ func AdminOrJobCreaterRightForTrain(ctx *context.Context) {


} }


func GenerateTask(ctx *context.Context, displayJobName, jobName, image, command, uuid, codePath, modelPath, benchmarkPath, snn4imagenetPath, brainScorePath, jobType, gpuQueue, description string, benchmarkTypeID, benchmarkChildTypeID, resourceSpecId int) error {
func GenerateTask(ctx *context.Context, displayJobName, jobName, image, command, uuid, codePath, modelPath, benchmarkPath, snn4imagenetPath, brainScorePath, jobType, gpuQueue, description, branchName, bootFile, params string, benchmarkTypeID, benchmarkChildTypeID, resourceSpecId int) error {
dataActualPath := setting.Attachment.Minio.RealPath + dataActualPath := setting.Attachment.Minio.RealPath +
setting.Attachment.Minio.Bucket + "/" + setting.Attachment.Minio.Bucket + "/" +
setting.Attachment.Minio.BasePath + setting.Attachment.Minio.BasePath +
@@ -155,13 +157,27 @@ func GenerateTask(ctx *context.Context, displayJobName, jobName, image, command,
uuid uuid


var resourceSpec *models.ResourceSpec var resourceSpec *models.ResourceSpec
if ResourceSpecs == nil {
json.Unmarshal([]byte(setting.ResourceSpecs), &ResourceSpecs)
}
for _, spec := range ResourceSpecs.ResourceSpec {
if resourceSpecId == spec.Id {
resourceSpec = spec
var versionCount int
if jobType == string(models.JobTypeTrain) {
versionCount = 1
if TrainResourceSpecs == nil {
json.Unmarshal([]byte(setting.TrainResourceSpecs), &TrainResourceSpecs)
}
for _, spec := range TrainResourceSpecs.ResourceSpec {
if resourceSpecId == spec.Id {
resourceSpec = spec
}
}
} else {
if ResourceSpecs == nil {
json.Unmarshal([]byte(setting.ResourceSpecs), &ResourceSpecs)
}
for _, spec := range ResourceSpecs.ResourceSpec {
if resourceSpecId == spec.Id {
resourceSpec = spec
}
} }

} }


if resourceSpec == nil { if resourceSpec == nil {
@@ -169,6 +185,15 @@ func GenerateTask(ctx *context.Context, displayJobName, jobName, image, command,
return errors.New("no such resourceSpec") return errors.New("no such resourceSpec")
} }


var datasetName string
attach, err := models.GetAttachmentByUUID(uuid)
if err != nil {
//for benchmark, do not return error
log.Error("GetAttachmentByUUID failed:%v", err)
} else {
datasetName = attach.Name
}

jobResult, err := CreateJob(jobName, models.CreateJobParams{ jobResult, err := CreateJob(jobName, models.CreateJobParams{
JobName: jobName, JobName: jobName,
RetryCount: 1, RetryCount: 1,
@@ -263,13 +288,19 @@ func GenerateTask(ctx *context.Context, displayJobName, jobName, image, command,
BenchmarkTypeID: benchmarkTypeID, BenchmarkTypeID: benchmarkTypeID,
BenchmarkChildTypeID: benchmarkChildTypeID, BenchmarkChildTypeID: benchmarkChildTypeID,
Description: description, Description: description,
IsLatestVersion: "1",
VersionCount: versionCount,
BranchName: branchName,
BootFile: bootFile,
DatasetName: datasetName,
Parameters: params,
}) })


if err != nil { if err != nil {
return err return err
} }


task, err := models.GetCloudbrainByName(jobName)
task, err := models.GetCloudbrainByJobID(jobID)
if err != nil { if err != nil {
log.Error("GetCloudbrainByName failed: %v", err.Error()) log.Error("GetCloudbrainByName failed: %v", err.Error())
return err return err
@@ -278,6 +309,8 @@ func GenerateTask(ctx *context.Context, displayJobName, jobName, image, command,


if string(models.JobTypeBenchmark) == jobType { if string(models.JobTypeBenchmark) == jobType {
notification.NotifyOtherTask(ctx.User, ctx.Repo.Repository, stringId, displayJobName, models.ActionCreateBenchMarkTask) notification.NotifyOtherTask(ctx.User, ctx.Repo.Repository, stringId, displayJobName, models.ActionCreateBenchMarkTask)
} else if string(models.JobTypeTrain) == jobType {
notification.NotifyOtherTask(ctx.User, ctx.Repo.Repository, jobID, displayJobName, models.ActionCreateGPUTrainTask)
} else { } else {
notification.NotifyOtherTask(ctx.User, ctx.Repo.Repository, stringId, displayJobName, models.ActionCreateDebugGPUTask) notification.NotifyOtherTask(ctx.User, ctx.Repo.Repository, stringId, displayJobName, models.ActionCreateDebugGPUTask)
} }
@@ -407,8 +440,10 @@ func RestartTask(ctx *context.Context, task *models.Cloudbrain, newID *string) e
return err return err
} }


idString := strconv.FormatInt(newTask.ID, 10)
*newID = idString
stringId := strconv.FormatInt(newTask.ID, 10)
*newID = stringId

notification.NotifyOtherTask(ctx.User, ctx.Repo.Repository, stringId, task.DisplayJobName, models.ActionCreateDebugGPUTask)


return nil return nil
} }

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

@@ -185,6 +185,17 @@ func registerHandleSummaryStatistic() {
}) })
} }


func registerHandleOrgStatistic() {
RegisterTaskFatal("handle_org_statistic", &BaseConfig{
Enabled: true,
RunAtStart: false,
Schedule: "0 0 2 * * ?",
}, func(ctx context.Context, _ *models.User, _ Config) error {
models.UpdateOrgStatistics()
return nil
})
}

func registerSyncCloudbrainStatus() { func registerSyncCloudbrainStatus() {
RegisterTaskFatal("sync_cloudbrain_status", &BaseConfig{ RegisterTaskFatal("sync_cloudbrain_status", &BaseConfig{
Enabled: true, Enabled: true,
@@ -215,4 +226,5 @@ func initBasicTasks() {
registerHandleSummaryStatistic() registerHandleSummaryStatistic()


registerSyncCloudbrainStatus() registerSyncCloudbrainStatus()
registerHandleOrgStatistic()
} }

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

@@ -56,7 +56,6 @@ const (
PerPage = 10 PerPage = 10
IsLatestVersion = "1" IsLatestVersion = "1"
NotLatestVersion = "0" NotLatestVersion = "0"
DebugType = -1
VersionCount = 1 VersionCount = 1


SortByCreateTime = "create_time" SortByCreateTime = "create_time"
@@ -281,6 +280,7 @@ func GenerateNotebook2(ctx *context.Context, displayJobName, jobName, uuid, desc
RepoID: ctx.Repo.Repository.ID, RepoID: ctx.Repo.Repository.ID,
JobID: jobResult.ID, JobID: jobResult.ID,
JobName: jobName, JobName: jobName,
FlavorCode: flavor,
DisplayJobName: displayJobName, DisplayJobName: displayJobName,
JobType: string(models.JobTypeDebug), JobType: string(models.JobTypeDebug),
Type: models.TypeCloudBrainTwo, Type: models.TypeCloudBrainTwo,


+ 16
- 11
modules/setting/setting.go View File

@@ -437,7 +437,7 @@ var (


//home page //home page
RecommentRepoAddr string RecommentRepoAddr string
ESSearchURL string
//notice config //notice config
UserNameOfNoticeRepo string UserNameOfNoticeRepo string
RepoNameOfNoticeRepo string RepoNameOfNoticeRepo string
@@ -452,16 +452,18 @@ var (
DecompressOBSTaskName string DecompressOBSTaskName string


//cloudbrain config //cloudbrain config
CBAuthUser string
CBAuthPassword string
RestServerHost string
JobPath string
CBCodePathPrefix string
JobType string
GpuTypes string
DebugServerHost string
ResourceSpecs string
MaxDuration int64
CBAuthUser string
CBAuthPassword string
RestServerHost string
JobPath string
CBCodePathPrefix string
JobType string
GpuTypes string
DebugServerHost string
ResourceSpecs string
MaxDuration int64
TrainGpuTypes string
TrainResourceSpecs string


//benchmark config //benchmark config
IsBenchmarkEnabled bool IsBenchmarkEnabled bool
@@ -1265,6 +1267,7 @@ func NewContext() {


sec = Cfg.Section("homepage") sec = Cfg.Section("homepage")
RecommentRepoAddr = sec.Key("Address").MustString("https://git.openi.org.cn/OpenIOSSG/promote/raw/branch/master/") RecommentRepoAddr = sec.Key("Address").MustString("https://git.openi.org.cn/OpenIOSSG/promote/raw/branch/master/")
ESSearchURL = sec.Key("ESSearchURL").MustString("http://192.168.207.94:9200")


sec = Cfg.Section("notice") sec = Cfg.Section("notice")
UserNameOfNoticeRepo = sec.Key("USER_NAME").MustString("OpenIOSSG") UserNameOfNoticeRepo = sec.Key("USER_NAME").MustString("OpenIOSSG")
@@ -1285,6 +1288,8 @@ func NewContext() {
GpuTypes = sec.Key("GPU_TYPES").MustString("") GpuTypes = sec.Key("GPU_TYPES").MustString("")
ResourceSpecs = sec.Key("RESOURCE_SPECS").MustString("") ResourceSpecs = sec.Key("RESOURCE_SPECS").MustString("")
MaxDuration = sec.Key("MAX_DURATION").MustInt64(14400) MaxDuration = sec.Key("MAX_DURATION").MustInt64(14400)
TrainGpuTypes = sec.Key("TRAIN_GPU_TYPES").MustString("")
TrainResourceSpecs = sec.Key("TRAIN_RESOURCE_SPECS").MustString("")


sec = Cfg.Section("benchmark") sec = Cfg.Section("benchmark")
IsBenchmarkEnabled = sec.Key("ENABLED").MustBool(false) IsBenchmarkEnabled = sec.Key("ENABLED").MustBool(false)


+ 34
- 3
options/locale/locale_en-US.ini View File

@@ -254,6 +254,18 @@ page_dev_yunlao_desc3=Developers can freely choose the corresponding computing r
page_dev_yunlao_desc4=If your model requires more computing resources, you can also apply for it separately. page_dev_yunlao_desc4=If your model requires more computing resources, you can also apply for it separately.
page_dev_yunlao_apply=Apply Separately page_dev_yunlao_apply=Apply Separately


search=Search
search_repo=Repository
search_dataset=DataSet
search_issue=Issue
search_pr=Pull Request
search_user=User
search_org=Organization
search_finded=Find
search_related=related
search_maybe=maybe
search_ge=

[explore] [explore]
repos = Repositories repos = Repositories
select_repos = Select the project select_repos = Select the project
@@ -481,6 +493,11 @@ static.encyclopediascount=Encyclopedias Count
static.createrepocount=Create Repo Count static.createrepocount=Create Repo Count
static.openiindex=OpenI Index static.openiindex=OpenI Index
static.registdate=Regist Date static.registdate=Regist Date
static.CloudBrainTaskNum=CloudBrain Task Count
static.CloudBrainRunTime=CloudBrain Run Time
static.CommitDatasetNum=Commit Dataset Count
static.CommitModelCount=Commit Model Count
static.UserIndex=User Index
static.countdate=Count Date static.countdate=Count Date
static.all=All static.all=All
static.public.user_business_analysis_current_month=Current_Month static.public.user_business_analysis_current_month=Current_Month
@@ -899,7 +916,9 @@ language_other = Other
datasets = Datasets datasets = Datasets
datasets.desc = Enable Dataset datasets.desc = Enable Dataset
cloudbrain_helper=Use GPU/NPU resources to open notebooks, model training tasks, etc. cloudbrain_helper=Use GPU/NPU resources to open notebooks, model training tasks, etc.

cloudbrain.exitinfo=Exit Information
cloudbrain.platform=Platform
cloudbrain.endtime=End Time
model_manager = Model model_manager = Model
model_noright=No right model_noright=No right
model_rename=Duplicate model name, please modify model name. model_rename=Duplicate model name, please modify model name.
@@ -1010,7 +1029,8 @@ modelarts.train_job.parameter_value=Parameter Value
modelarts.train_job.resource_setting=resource_setting modelarts.train_job.resource_setting=resource_setting
modelarts.train_job.resource_setting_info=resource_setting_info modelarts.train_job.resource_setting_info=resource_setting_info
modelarts.train_job.resource_pool=resource_pool modelarts.train_job.resource_pool=resource_pool
modelarts.train_job.resource_type=resource_type
modelarts.train_job.resource_type=Resource Type
modelarts.train_job.train_dataset=Train Dataset
modelarts.train_job.standard=Standard modelarts.train_job.standard=Standard
modelarts.train_job.NAS_address=NAS Address modelarts.train_job.NAS_address=NAS Address
modelarts.train_job.NAS_mount_path=NAS Mount Path modelarts.train_job.NAS_mount_path=NAS Mount Path
@@ -2182,6 +2202,16 @@ customize = Customize
selected_project=Selected Projects selected_project=Selected Projects
fold = Fold fold = Fold
unfold = Unfold unfold = Unfold
org_member = Member
org_members = Members
org_team = Team
org_teams = Teams
org_repository = Repository
org_repositories = Repositories

star = Star Top10
member = Members Top10
active = Active Top10


form.name_reserved = The organization name '%s' is reserved. form.name_reserved = The organization name '%s' is reserved.
form.name_pattern_not_allowed = The pattern '%s' is not allowed in an organization name. form.name_pattern_not_allowed = The pattern '%s' is not allowed in an organization name.
@@ -2794,10 +2824,11 @@ reject_pull_request = `suggested changes for <a href="%s/pulls/%s">%s#%[2]s</a>`
upload_dataset=`upload dataset <a href="%s/datasets?type=%s">%s</a>` upload_dataset=`upload dataset <a href="%s/datasets?type=%s">%s</a>`
task_gpudebugjob=`created CPU/GPU type debugging task<a href="%s/cloudbrain/%s">%s</a>` task_gpudebugjob=`created CPU/GPU type debugging task<a href="%s/cloudbrain/%s">%s</a>`
task_npudebugjob=`created NPU type debugging task <a href="%s/modelarts/notebook/%s">%s</a>` task_npudebugjob=`created NPU type debugging task <a href="%s/modelarts/notebook/%s">%s</a>`
task_trainjob=`created training task<a href="%s/modelarts/train-job/%s">%s</a>`
task_nputrainjob=`created NPU training task<a href="%s/modelarts/train-job/%s">%s</a>`
task_inferencejob=`created reasoning task <a href="%s/modelarts/inference-job/%s">%s</a>` task_inferencejob=`created reasoning task <a href="%s/modelarts/inference-job/%s">%s</a>`
task_benchmark=`created profiling task <a href="%s/cloudbrain/benchmark/%s">%s</a>` task_benchmark=`created profiling task <a href="%s/cloudbrain/benchmark/%s">%s</a>`
task_createmodel=`created new model <a href="%s/modelmanage/show_model_info?name=%s">%s</a>` task_createmodel=`created new model <a href="%s/modelmanage/show_model_info?name=%s">%s</a>`
task_gputrainjob=`created CPU/GPU training task<a href="%s/cloudbrain/train-job/%s">%s</a>`


[tool] [tool]
ago = %s ago ago = %s ago


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

@@ -256,6 +256,18 @@ page_dev_yunlao_desc3=开发者可以根据使用需求,自由选择相应计
page_dev_yunlao_desc4=如果您的模型需要更多的计算资源,也可以单独申请 page_dev_yunlao_desc4=如果您的模型需要更多的计算资源,也可以单独申请
page_dev_yunlao_apply=单独申请 page_dev_yunlao_apply=单独申请


search=搜索
search_repo=项目
search_dataset=数据集
search_issue=任务
search_pr=合并请求
search_user=用户
search_org=组织
search_finded=找到
search_related=相关
search_maybe=约为
search_ge=个

[explore] [explore]
repos=项目 repos=项目
select_repos=精选项目 select_repos=精选项目
@@ -484,6 +496,11 @@ static.encyclopediascount=百科页面贡献次数
static.createrepocount=创建项目数 static.createrepocount=创建项目数
static.openiindex=OpenI指数 static.openiindex=OpenI指数
static.registdate=用户注册时间 static.registdate=用户注册时间
static.CloudBrainTaskNum=云脑任务数
static.CloudBrainRunTime=云脑运行时间(小时)
static.CommitDatasetNum=上传(提交)数据集文件数
static.CommitModelCount=提交模型数
static.UserIndex=用户指数
static.countdate=系统统计时间 static.countdate=系统统计时间
static.all=所有 static.all=所有
static.public.user_business_analysis_current_month=本月 static.public.user_business_analysis_current_month=本月
@@ -946,7 +963,9 @@ cloudbrain_jobname_err=只能以小写字母或数字开头且只包含小写字
cloudbrain_query_fail=查询云脑任务失败。 cloudbrain_query_fail=查询云脑任务失败。
cloudbrain.mirror_tag = 镜像标签 cloudbrain.mirror_tag = 镜像标签
cloudbrain.mirror_description = 镜像描述 cloudbrain.mirror_description = 镜像描述

cloudbrain.exitinfo=退出信息
cloudbrain.platform=平台
cloudbrain.endtime=结束时间
record_begintime_get_err=无法获取统计开始时间。 record_begintime_get_err=无法获取统计开始时间。
parameter_is_wrong=输入参数错误,请检查输入参数。 parameter_is_wrong=输入参数错误,请检查输入参数。
total_count_get_error=查询总页数失败。 total_count_get_error=查询总页数失败。
@@ -2187,6 +2206,16 @@ customize = 自定义
selected_project=精选项目 selected_project=精选项目
fold = 收起 fold = 收起
unfold = 展开 unfold = 展开
org_member = 成员
org_members = 成员
org_team = 团队
org_teams = 团队
org_repository = 项目
org_repositories = 项目

star = 点赞榜
member = 成员榜
active = 活跃榜


form.name_reserved=组织名称 '%s' 是被保留的。 form.name_reserved=组织名称 '%s' 是被保留的。
form.name_pattern_not_allowed=组织名称中不允许使用 "%s"。 form.name_pattern_not_allowed=组织名称中不允许使用 "%s"。
@@ -2800,10 +2829,11 @@ reject_pull_request=`建议变更 <a href="%s/pulls/%s">%s#%[2]s</a>`
upload_dataset=`上传了数据集文件 <a href="%s/datasets?type=%s">%s</a>` upload_dataset=`上传了数据集文件 <a href="%s/datasets?type=%s">%s</a>`
task_gpudebugjob=`创建了CPU/GPU类型调试任务 <a href="%s/cloudbrain/%s">%s</a>` task_gpudebugjob=`创建了CPU/GPU类型调试任务 <a href="%s/cloudbrain/%s">%s</a>`
task_npudebugjob=`创建了NPU类型调试任务 <a href="%s/modelarts/notebook/%s">%s</a>` task_npudebugjob=`创建了NPU类型调试任务 <a href="%s/modelarts/notebook/%s">%s</a>`
task_trainjob=`创建了训练任务 <a href="%s/modelarts/train-job/%s">%s</a>`
task_nputrainjob=`创建了NPU类型训练任务 <a href="%s/modelarts/train-job/%s">%s</a>`
task_inferencejob=`创建了推理任务 <a href="%s/modelarts/inference-job/%s">%s</a>` task_inferencejob=`创建了推理任务 <a href="%s/modelarts/inference-job/%s">%s</a>`
task_benchmark=`创建了评测任务 <a href="%s/cloudbrain/benchmark/%s">%s</a>` task_benchmark=`创建了评测任务 <a href="%s/cloudbrain/benchmark/%s">%s</a>`
task_createmodel=`导入了新模型 <a href="%s/modelmanage/show_model_info?name=%s">%s</a>` task_createmodel=`导入了新模型 <a href="%s/modelmanage/show_model_info?name=%s">%s</a>`
task_gputrainjob=`创建了CPU/GPU类型训练任务 <a href="%s/cloudbrain/train-job/%s">%s</a>`


[tool] [tool]
ago=%s前 ago=%s前


+ 9
- 5
public/home/home.js View File

@@ -135,7 +135,7 @@ socket.onmessage = function (e) {
html += recordPrefix + actionName; html += recordPrefix + actionName;
html += " <a href=\"" + getRepoLink(record) + "\" rel=\"nofollow\">" + getRepotext(record) + "</a>" html += " <a href=\"" + getRepoLink(record) + "\" rel=\"nofollow\">" + getRepotext(record) + "</a>"
} }
else if(record.OpType == "24" || record.OpType == "26" || record.OpType == "27" || record.OpType == "28" || record.OpType == "30"){
else if(record.OpType == "24" || record.OpType == "26" || record.OpType == "27" || record.OpType == "28" || record.OpType == "30" || record.OpType == "31"){
html += recordPrefix + actionName; html += recordPrefix + actionName;
html += " <a href=\"" + getTaskLink(record) + "\" rel=\"nofollow\">" + record.RefName + "</a>" html += " <a href=\"" + getTaskLink(record) + "\" rel=\"nofollow\">" + record.RefName + "</a>"
} }
@@ -175,6 +175,8 @@ function getTaskLink(record){
re = re + "/cloudbrain/benchmark/" + record.Content; re = re + "/cloudbrain/benchmark/" + record.Content;
}else if(record.OpType == 30){ }else if(record.OpType == 30){
re = re + "/modelmanage/show_model_info?name=" + record.RefName; re = re + "/modelmanage/show_model_info?name=" + record.RefName;
}else if(record.OpType == 31){
re = re + "/cloudbrain/train-job/" + record.Content;
} }
re = encodeURI(re); re = encodeURI(re);
return re; return re;
@@ -321,10 +323,11 @@ var actionNameZH={
"24":"上传了数据集文件", "24":"上传了数据集文件",
"25":"创建了CPU/GPU类型调试任务", "25":"创建了CPU/GPU类型调试任务",
"26":"创建了NPU类型调试任务", "26":"创建了NPU类型调试任务",
"27":"创建了训练任务",
"27":"创建了NPU类型训练任务",
"28":"创建了推理任务", "28":"创建了推理任务",
"29":"创建了评测任务", "29":"创建了评测任务",
"30":"导入了新模型"
"30":"导入了新模型",
"31":"创建了CPU/GPU类型训练任务"
}; };


var actionNameEN={ var actionNameEN={
@@ -346,10 +349,11 @@ var actionNameEN={
"24":" upload dataset ", "24":" upload dataset ",
"25":" created CPU/GPU type debugging task ", "25":" created CPU/GPU type debugging task ",
"26":" created NPU type debugging task ", "26":" created NPU type debugging task ",
"27":" created training task",
"27":" created NPU type training task",
"28":" created reasoning task", "28":" created reasoning task",
"29":" created profiling task", "29":" created profiling task",
"30":" created new model"
"30":" created new model",
"31":" created CPU/GPU type training task",
}; };


var repoAndOrgZH={ var repoAndOrgZH={


+ 1305
- 0
public/home/search.js
File diff suppressed because it is too large
View File


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

@@ -620,10 +620,10 @@ function showfilelist(){
for (var i=0;i<labeltastresult.length;i++){ for (var i=0;i<labeltastresult.length;i++){
var fname = labeltastresult[i].pic_image_field.substring(labeltastresult[i].pic_image_field.lastIndexOf('/') + 1); var fname = labeltastresult[i].pic_image_field.substring(labeltastresult[i].pic_image_field.lastIndexOf('/') + 1);
console.log(labeltastresult[i])
//console.log(labeltastresult[i])
if(labeltastresult[i].pic_image_field.length > 70){ if(labeltastresult[i].pic_image_field.length > 70){
var tmpIndex = labeltastresult[i].pic_image_field.indexOf("/",70); var tmpIndex = labeltastresult[i].pic_image_field.indexOf("/",70);
console.log(tmpIndex)
//console.log(tmpIndex)
if(tmpIndex != -1){ if(tmpIndex != -1){
fname = labeltastresult[i].pic_image_field.substring(tmpIndex + 1); fname = labeltastresult[i].pic_image_field.substring(tmpIndex + 1);
fname = fname.substring(fname.indexOf('/')+1); fname = fname.substring(fname.indexOf('/')+1);
@@ -679,7 +679,7 @@ function breadFiles(){
fname_full_path = tableData[fileindex].pic_image_field.substring(tmp_index + 1); fname_full_path = tableData[fileindex].pic_image_field.substring(tmp_index + 1);
} }
var fname_path = fname_full_path.split('/') var fname_path = fname_full_path.split('/')
console.log(fname_path)
//console.log(fname_path)
// var filename_text = tableData[fileindex].pic_image_field.substring(tableData[fileindex].pic_image_field.lastIndexOf('/')+1) // var filename_text = tableData[fileindex].pic_image_field.substring(tableData[fileindex].pic_image_field.lastIndexOf('/')+1)
var html_breadFile = '' var html_breadFile = ''
// var source_name = filename_title+'.zip' // var source_name = filename_title+'.zip'


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

@@ -41,7 +41,7 @@ func CloudBrains(ctx *context.Context) {
if page <= 0 { if page <= 0 {
page = 1 page = 1
} }
debugType := modelarts.DebugType
debugType := models.TypeCloudBrainAll
if listType == models.GPUResource { if listType == models.GPUResource {
debugType = models.TypeCloudBrainOne debugType = models.TypeCloudBrainOne
} else if listType == models.NPUResource { } else if listType == models.NPUResource {
@@ -121,7 +121,7 @@ func DownloadCloudBrains(ctx *context.Context) {
Page: page, Page: page,
PageSize: 1, PageSize: 1,
}, },
Type: modelarts.DebugType,
Type: models.TypeCloudBrainAll,
NeedRepoInfo: false, NeedRepoInfo: false,
IsLatestVersion: modelarts.IsLatestVersion, IsLatestVersion: modelarts.IsLatestVersion,
}) })
@@ -151,7 +151,7 @@ func DownloadCloudBrains(ctx *context.Context) {
Page: page, Page: page,
PageSize: pageSize, PageSize: pageSize,
}, },
Type: modelarts.DebugType,
Type: models.TypeCloudBrainAll,
NeedRepoInfo: true, NeedRepoInfo: true,
IsLatestVersion: modelarts.IsLatestVersion, IsLatestVersion: modelarts.IsLatestVersion,
}) })


+ 12
- 2
routers/api/v1/api.go View File

@@ -62,10 +62,10 @@ import (
"net/http" "net/http"
"strings" "strings"


"code.gitea.io/gitea/routers/authentication"

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

"code.gitea.io/gitea/modules/cloudbrain"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
@@ -77,6 +77,7 @@ import (
"code.gitea.io/gitea/routers/api/v1/repo" "code.gitea.io/gitea/routers/api/v1/repo"
_ "code.gitea.io/gitea/routers/api/v1/swagger" // for swagger generation _ "code.gitea.io/gitea/routers/api/v1/swagger" // for swagger generation
"code.gitea.io/gitea/routers/api/v1/user" "code.gitea.io/gitea/routers/api/v1/user"
"code.gitea.io/gitea/routers/authentication"
repo_ext "code.gitea.io/gitea/routers/repo" repo_ext "code.gitea.io/gitea/routers/repo"


"gitea.com/macaron/binding" "gitea.com/macaron/binding"
@@ -546,6 +547,8 @@ func RegisterRoutes(m *macaron.Macaron) {
}) })
}, operationReq) }, operationReq)


m.Get("/query_user_metrics", operationReq, repo_ext.QueryMetrics)
m.Get("/query_user_rank_list", operationReq, repo_ext.QueryRankingList)
m.Get("/query_user_static_page", operationReq, repo_ext.QueryUserStaticDataPage) m.Get("/query_user_static_page", operationReq, repo_ext.QueryUserStaticDataPage)
m.Get("/query_user_current_month", operationReq, repo_ext.QueryUserStaticCurrentMonth) m.Get("/query_user_current_month", operationReq, repo_ext.QueryUserStaticCurrentMonth)
m.Get("/query_user_current_week", operationReq, repo_ext.QueryUserStaticCurrentWeek) m.Get("/query_user_current_week", operationReq, repo_ext.QueryUserStaticCurrentWeek)
@@ -882,6 +885,13 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Group("/cloudbrain", func() { m.Group("/cloudbrain", func() {
m.Get("/:id", repo.GetCloudbrainTask) m.Get("/:id", repo.GetCloudbrainTask)
m.Get("/:id/log", repo.CloudbrainGetLog) m.Get("/:id/log", repo.CloudbrainGetLog)
m.Group("/train-job", func() {
m.Group("/:jobid", func() {
m.Get("", repo.GetModelArtsTrainJobVersion)
m.Get("/model_list", repo.CloudBrainModelList)
m.Post("/stop_version", cloudbrain.AdminOrOwnerOrJobCreaterRightForTrain, repo_ext.CloudBrainStop)
})
})
}, reqRepoReader(models.UnitTypeCloudBrain)) }, reqRepoReader(models.UnitTypeCloudBrain))
m.Group("/modelarts", func() { m.Group("/modelarts", func() {
m.Group("/notebook", func() { m.Group("/notebook", func() {


+ 61
- 15
routers/api/v1/repo/cloudbrain.go View File

@@ -6,16 +6,18 @@
package repo package repo


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


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

"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/cloudbrain" "code.gitea.io/gitea/modules/cloudbrain"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/storage"
routerRepo "code.gitea.io/gitea/routers/repo"
) )


// cloudbrain get job task by jobid // cloudbrain get job task by jobid
@@ -63,7 +65,7 @@ func GetCloudbrainTask(ctx *context.APIContext) {
log.Error("GetJob failed:", err) log.Error("GetJob failed:", err)
return return
} }
result, err := models.ConvertToJobResultPayload(jobResult.Payload)
result, _ := models.ConvertToJobResultPayload(jobResult.Payload)
if err != nil { if err != nil {
ctx.NotFound(err) ctx.NotFound(err)
log.Error("ConvertToJobResultPayload failed:", err) log.Error("ConvertToJobResultPayload failed:", err)
@@ -71,24 +73,16 @@ func GetCloudbrainTask(ctx *context.APIContext) {
} }


job.Status = result.JobStatus.State job.Status = result.JobStatus.State
taskRoles := result.TaskRoles
taskRes, _ := models.ConvertToTaskPod(taskRoles[cloudbrain.SubTaskName].(map[string]interface{}))
if result.JobStatus.State != string(models.JobWaiting) && result.JobStatus.State != string(models.JobFailed) { if result.JobStatus.State != string(models.JobWaiting) && result.JobStatus.State != string(models.JobFailed) {
taskRoles := result.TaskRoles
taskRes, _ := models.ConvertToTaskPod(taskRoles[cloudbrain.SubTaskName].(map[string]interface{}))

job.ContainerIp = taskRes.TaskStatuses[0].ContainerIP job.ContainerIp = taskRes.TaskStatuses[0].ContainerIP
job.ContainerID = taskRes.TaskStatuses[0].ContainerID job.ContainerID = taskRes.TaskStatuses[0].ContainerID
job.Status = taskRes.TaskStatuses[0].State job.Status = taskRes.TaskStatuses[0].State

if job.StartTime == 0 && !taskRes.TaskStatuses[0].StartAt.IsZero() {
job.StartTime = timeutil.TimeStamp(taskRes.TaskStatuses[0].StartAt.Unix())
}
} }


if result.JobStatus.State != string(models.JobWaiting) { if result.JobStatus.State != string(models.JobWaiting) {
if job.EndTime == 0 && models.IsCloudBrainOneDebugJobTerminal(job.Status) {
job.EndTime = timeutil.TimeStampNow()
}
job.ComputeAndSetDuration()
models.ParseAndSetDurationFromCloudBrainOne(result, job)
err = models.UpdateJob(job) err = models.UpdateJob(job)
if err != nil { if err != nil {
log.Error("UpdateJob failed:", err) log.Error("UpdateJob failed:", err)
@@ -161,3 +155,55 @@ func CloudbrainGetLog(ctx *context.Context) {


return return
} }

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

var jobID = ctx.Params(":jobid")
var versionName = ctx.Query("version_name")
parentDir := ctx.Query("parentDir")
dirArray := strings.Split(parentDir, "/")

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

//get dirs
dirs, err := routerRepo.GetModelDirs(task.JobName, parentDir)
if err != nil {
log.Error("GetModelDirs failed:%v", err.Error(), ctx.Data["msgID"])
ctx.ServerError("GetModelDirs failed:", err)
return
}

var fileInfos []storage.FileInfo
err = json.Unmarshal([]byte(dirs), &fileInfos)
if err != nil {
log.Error("json.Unmarshal failed:%v", err.Error(), ctx.Data["msgID"])
ctx.ServerError("json.Unmarshal failed:", err)
return
}

for i, fileInfo := range fileInfos {
temp, _ := time.Parse("2006-01-02 15:04:05", fileInfo.ModTime)
fileInfos[i].ModTime = temp.Local().Format("2006-01-02 15:04:05")
}

sort.Slice(fileInfos, func(i, j int) bool {
return fileInfos[i].ModTime > fileInfos[j].ModTime
})

ctx.JSON(http.StatusOK, map[string]interface{}{
"JobID": jobID,
"VersionName": versionName,
"StatusOK": 0,
"Path": dirArray,
"Dirs": fileInfos,
"task": task,
"PageIsCloudBrain": true,
})
}

+ 57
- 24
routers/api/v1/repo/modelarts.go View File

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


import ( import (
"code.gitea.io/gitea/modules/timeutil"
"net/http" "net/http"
"strconv" "strconv"
"strings" "strings"


"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/cloudbrain"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/modelarts" "code.gitea.io/gitea/modules/modelarts"
"code.gitea.io/gitea/modules/storage" "code.gitea.io/gitea/modules/storage"
"code.gitea.io/gitea/modules/timeutil"
routerRepo "code.gitea.io/gitea/routers/repo" routerRepo "code.gitea.io/gitea/routers/repo"
) )


@@ -66,8 +67,8 @@ func GetModelArtsNotebook2(ctx *context.APIContext) {
ctx.NotFound(err) ctx.NotFound(err)
return return
} }
if job.StartTime == 0 && result.Lease.CreateTime > 0 {
job.StartTime = timeutil.TimeStamp(result.Lease.CreateTime / 1000)
if job.StartTime == 0 && result.Lease.UpdateTime > 0 {
job.StartTime = timeutil.TimeStamp(result.Lease.UpdateTime / 1000)
} }
job.Status = result.Status job.Status = result.Status
if job.EndTime == 0 && models.IsModelArtsDebugJobTerminal(job.Status) { if job.EndTime == 0 && models.IsModelArtsDebugJobTerminal(job.Status) {
@@ -133,27 +134,61 @@ func GetModelArtsTrainJobVersion(ctx *context.APIContext) {
ctx.NotFound(err) ctx.NotFound(err)
return return
} }
result, err := modelarts.GetTrainJob(jobID, strconv.FormatInt(job.VersionID, 10))
if err != nil {
ctx.NotFound(err)
return
}
if job.StartTime == 0 && result.StartTime > 0 {
job.StartTime = timeutil.TimeStamp(result.StartTime / 1000)
}
job.Status = modelarts.TransTrainJobStatus(result.IntStatus)
job.Duration = result.Duration / 1000
job.TrainJobDuration = result.TrainJobDuration


job.TrainJobDuration = models.ConvertDurationToStr(job.Duration)
if job.Type == models.TypeCloudBrainOne {
jobResult, err := cloudbrain.GetJob(job.JobID)
if err != nil {
ctx.NotFound(err)
log.Error("GetJob failed:", err)
return
}
result, err := models.ConvertToJobResultPayload(jobResult.Payload)
if err != nil {
ctx.NotFound(err)
log.Error("ConvertToJobResultPayload failed:", err)
return
}


if job.EndTime == 0 && models.IsTrainJobTerminal(job.Status) && job.StartTime > 0 {
job.EndTime = job.StartTime.Add(job.Duration)
}
job.Status = result.JobStatus.State
if result.JobStatus.State != string(models.JobWaiting) && result.JobStatus.State != string(models.JobFailed) {
taskRoles := result.TaskRoles
taskRes, _ := models.ConvertToTaskPod(taskRoles[cloudbrain.SubTaskName].(map[string]interface{}))


err = models.UpdateTrainJobVersion(job)
if err != nil {
log.Error("UpdateJob failed:", err)
job.ContainerIp = taskRes.TaskStatuses[0].ContainerIP
job.ContainerID = taskRes.TaskStatuses[0].ContainerID
job.Status = taskRes.TaskStatuses[0].State
}

if result.JobStatus.State != string(models.JobWaiting) {
err = models.UpdateJob(job)
if err != nil {
log.Error("UpdateJob failed:", err)
}
}
} else {
result, err := modelarts.GetTrainJob(jobID, strconv.FormatInt(job.VersionID, 10))
if err != nil {
ctx.NotFound(err)
return
}

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

job.TrainJobDuration = models.ConvertDurationToStr(job.Duration)

if job.EndTime == 0 && models.IsTrainJobTerminal(job.Status) && job.StartTime > 0 {
job.EndTime = job.StartTime.Add(job.Duration)
}

err = models.UpdateTrainJobVersion(job)
if err != nil {
log.Error("UpdateJob failed:", err)
}
} }


ctx.JSON(http.StatusOK, map[string]interface{}{ ctx.JSON(http.StatusOK, map[string]interface{}{
@@ -377,9 +412,7 @@ func GetModelArtsInferenceJob(ctx *context.APIContext) {
} }
job.Status = modelarts.TransTrainJobStatus(result.IntStatus) job.Status = modelarts.TransTrainJobStatus(result.IntStatus)
job.Duration = result.Duration / 1000 job.Duration = result.Duration / 1000
job.TrainJobDuration = result.TrainJobDuration

job.TrainJobDuration = models.ConvertDurationToStr(result.Duration)
job.TrainJobDuration = models.ConvertDurationToStr(job.Duration)


if job.EndTime == 0 && models.IsTrainJobTerminal(job.Status) && job.StartTime > 0 { if job.EndTime == 0 && models.IsTrainJobTerminal(job.Status) && job.StartTime > 0 {
job.EndTime = job.StartTime.Add(job.Duration) job.EndTime = job.StartTime.Add(job.Duration)


+ 47
- 13
routers/home.go View File

@@ -49,7 +49,7 @@ func Home(ctx *context.Context) {
ctx.HTML(200, tplHome) ctx.HTML(200, tplHome)
} }


func setRecommendURL(ctx *context.Context) {
func setRecommendURLOnly(ctx *context.Context) {
addr := setting.RecommentRepoAddr[10:] addr := setting.RecommentRepoAddr[10:]
start := strings.Index(addr, "/") start := strings.Index(addr, "/")
end := strings.Index(addr, "raw") end := strings.Index(addr, "raw")
@@ -58,7 +58,10 @@ func setRecommendURL(ctx *context.Context) {
} else { } else {
ctx.Data["RecommendURL"] = setting.RecommentRepoAddr ctx.Data["RecommendURL"] = setting.RecommentRepoAddr
} }
}


func setRecommendURL(ctx *context.Context) {
setRecommendURLOnly(ctx)
ctx.Data["page_title"] = ctx.Tr("home.page_title") ctx.Data["page_title"] = ctx.Tr("home.page_title")
ctx.Data["page_small_title"] = ctx.Tr("home.page_small_title") ctx.Data["page_small_title"] = ctx.Tr("home.page_small_title")
ctx.Data["page_description"] = ctx.Tr("home.page_description") ctx.Data["page_description"] = ctx.Tr("home.page_description")
@@ -441,17 +444,39 @@ func ExploreOrganizations(ctx *context.Context) {
ctx.Data["PageIsExploreOrganizations"] = true ctx.Data["PageIsExploreOrganizations"] = true
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled


visibleTypes := []structs.VisibleType{structs.VisibleTypePublic}
if ctx.User != nil {
visibleTypes = append(visibleTypes, structs.VisibleTypeLimited, structs.VisibleTypePrivate)
N := 10
starInfo, err := models.FindTopNStarsOrgs(N)
if err != nil {
log.Error("GetStarOrgInfos failed:%v", err.Error(), ctx.Data["MsgID"])
ctx.ServerError("GetStarOrgInfos", err)
return
}
memberInfo, err := models.FindTopNMembersOrgs(N)
if err != nil {
log.Error("GetMemberOrgInfos failed:%v", err.Error(), ctx.Data["MsgID"])
ctx.ServerError("GetMemberOrgInfos", err)
return
}
openIInfo, err := models.FindTopNOpenIOrgs(N)
if err != nil {
log.Error("GetOpenIOrgInfos failed:%v", err.Error(), ctx.Data["MsgID"])
ctx.ServerError("GetOpenIOrgInfos", err)
return
} }


RenderUserSearch(ctx, &models.SearchUserOptions{
Actor: ctx.User,
Type: models.UserTypeOrganization,
ListOptions: models.ListOptions{PageSize: setting.UI.ExplorePagingNum},
Visible: visibleTypes,
}, tplExploreOrganizations)
recommendOrgs, err := GetRecommendOrg()
if err != nil {
log.Error("GetRecommendOrgInfos failed:%v", err.Error(), ctx.Data["MsgID"])
ctx.ServerError("GetRecommendOrgInfos", err)
return
}
setRecommendURLOnly(ctx)
ctx.Data["RecommendOrgs"] = recommendOrgs
ctx.Data["StarOrgs"] = starInfo
ctx.Data["MemberOrgs"] = memberInfo
ctx.Data["ActiveOrgs"] = openIInfo

ctx.HTML(http.StatusOK, tplExploreOrganizations)
} }


// ExploreCode render explore code page // ExploreCode render explore code page
@@ -583,12 +608,12 @@ func NotFound(ctx *context.Context) {
ctx.NotFound("home.NotFound", nil) ctx.NotFound("home.NotFound", nil)
} }


func RecommendOrgFromPromote(ctx *context.Context) {
func GetRecommendOrg() ([]map[string]interface{}, error) {
url := setting.RecommentRepoAddr + "organizations" url := setting.RecommentRepoAddr + "organizations"
result, err := repository.RecommendFromPromote(url) result, err := repository.RecommendFromPromote(url)

if err != nil { if err != nil {
ctx.ServerError("500", err)
return
return nil, err
} }
resultOrg := make([]map[string]interface{}, 0) resultOrg := make([]map[string]interface{}, 0)
for _, userName := range result { for _, userName := range result {
@@ -598,6 +623,7 @@ func RecommendOrgFromPromote(ctx *context.Context) {
userMap["Name"] = user.Name userMap["Name"] = user.Name
userMap["Description"] = user.Description userMap["Description"] = user.Description
userMap["FullName"] = user.FullName userMap["FullName"] = user.FullName
userMap["HomeLink"] = user.HomeLink()
userMap["ID"] = user.ID userMap["ID"] = user.ID
userMap["Avatar"] = user.RelAvatarLink() userMap["Avatar"] = user.RelAvatarLink()
userMap["NumRepos"] = user.NumRepos userMap["NumRepos"] = user.NumRepos
@@ -608,7 +634,15 @@ func RecommendOrgFromPromote(ctx *context.Context) {
log.Info("query user error," + err.Error()) log.Info("query user error," + err.Error())
} }
} }
return resultOrg, nil
}


func RecommendOrgFromPromote(ctx *context.Context) {
resultOrg, err := GetRecommendOrg()
if err != nil {
ctx.ServerError("500", err)
return
}
ctx.JSON(200, resultOrg) ctx.JSON(200, resultOrg)
} }




+ 2
- 0
routers/init.go View File

@@ -71,6 +71,8 @@ func NewServices() {
log.Info("decompression.NewContext() succeed.") log.Info("decompression.NewContext() succeed.")
labelmsg.Init() labelmsg.Init()
log.Info("labelmsg.Init() succeed.") log.Info("labelmsg.Init() succeed.")
InitESClient()
log.Info("ES Client succeed.")
} }


// In case of problems connecting to DB, retry connection. Eg, PGSQL in Docker Container on Synology // In case of problems connecting to DB, retry connection. Eg, PGSQL in Docker Container on Synology


+ 4
- 0
routers/private/internal.go View File

@@ -6,6 +6,7 @@
package private package private


import ( import (
"code.gitea.io/gitea/routers/repo"
"strings" "strings"


"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
@@ -44,7 +45,10 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Post("/manager/flush-queues", bind(private.FlushOptions{}), FlushQueues) m.Post("/manager/flush-queues", bind(private.FlushOptions{}), FlushQueues)
m.Post("/tool/update_all_repo_commit_cnt", UpdateAllRepoCommitCnt) m.Post("/tool/update_all_repo_commit_cnt", UpdateAllRepoCommitCnt)
m.Post("/tool/repo_stat/:date", RepoStatisticManually) m.Post("/tool/repo_stat/:date", RepoStatisticManually)

m.Get("/tool/org_stat", OrgStatisticManually)
m.Post("/tool/update_repo_visit/:date", UpdateRepoVisit) m.Post("/tool/update_repo_visit/:date", UpdateRepoVisit)
m.Post("/task/history_handle/duration", repo.HandleTaskWithNoDuration)


}, CheckInternalToken) }, CheckInternalToken)
} }

+ 4
- 0
routers/private/tool.go View File

@@ -45,6 +45,10 @@ func RepoStatisticManually(ctx *macaron.Context) {
repo.TimingCountDataByDate(date) repo.TimingCountDataByDate(date)
} }


func OrgStatisticManually() {
models.UpdateOrgStatistics()
}

func UpdateRepoVisit(ctx *macaron.Context) { func UpdateRepoVisit(ctx *macaron.Context) {
date := ctx.Params("date") date := ctx.Params("date")
log.Info("date(%s)", date) log.Info("date(%s)", date)


+ 404
- 54
routers/repo/cloudbrain.go View File

@@ -2,11 +2,9 @@ package repo


import ( import (
"bufio" "bufio"
"code.gitea.io/gitea/modules/timeutil"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"github.com/unknwon/i18n"
"io" "io"
"net/http" "net/http"
"os" "os"
@@ -16,6 +14,9 @@ import (
"strings" "strings"
"time" "time"


"code.gitea.io/gitea/modules/timeutil"
"github.com/unknwon/i18n"

"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/auth" "code.gitea.io/gitea/modules/auth"
"code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/base"
@@ -37,6 +38,9 @@ const (
tplCloudBrainBenchmarkIndex base.TplName = "repo/cloudbrain/benchmark/index" tplCloudBrainBenchmarkIndex base.TplName = "repo/cloudbrain/benchmark/index"
tplCloudBrainBenchmarkNew base.TplName = "repo/cloudbrain/benchmark/new" tplCloudBrainBenchmarkNew base.TplName = "repo/cloudbrain/benchmark/new"
tplCloudBrainBenchmarkShow base.TplName = "repo/cloudbrain/benchmark/show" tplCloudBrainBenchmarkShow base.TplName = "repo/cloudbrain/benchmark/show"

tplCloudBrainTrainJobNew base.TplName = "repo/cloudbrain/trainjob/new"
tplCloudBrainTrainJobShow base.TplName = "repo/cloudbrain/trainjob/show"
) )


var ( var (
@@ -45,6 +49,7 @@ var (
benchmarkTypes *models.BenchmarkTypes benchmarkTypes *models.BenchmarkTypes
benchmarkGpuInfos *models.GpuInfos benchmarkGpuInfos *models.GpuInfos
benchmarkResourceSpecs *models.ResourceSpecs benchmarkResourceSpecs *models.ResourceSpecs
trainGpuInfos *models.GpuInfos
) )


const BENCHMARK_TYPE_CODE = "repo.cloudbrain.benchmark.types" const BENCHMARK_TYPE_CODE = "repo.cloudbrain.benchmark.types"
@@ -143,6 +148,11 @@ func cloudBrainNewDataPrepare(ctx *context.Context) error {
} }
ctx.Data["gpu_types"] = gpuInfos.GpuInfo ctx.Data["gpu_types"] = gpuInfos.GpuInfo


if trainGpuInfos == nil {
json.Unmarshal([]byte(setting.TrainGpuTypes), &trainGpuInfos)
}
ctx.Data["train_gpu_types"] = trainGpuInfos.GpuInfo

if benchmarkGpuInfos == nil { if benchmarkGpuInfos == nil {
json.Unmarshal([]byte(setting.BenchmarkGpuTypes), &benchmarkGpuInfos) json.Unmarshal([]byte(setting.BenchmarkGpuTypes), &benchmarkGpuInfos)
} }
@@ -157,6 +167,14 @@ func cloudBrainNewDataPrepare(ctx *context.Context) error {
json.Unmarshal([]byte(setting.ResourceSpecs), &cloudbrain.ResourceSpecs) json.Unmarshal([]byte(setting.ResourceSpecs), &cloudbrain.ResourceSpecs)
} }
ctx.Data["resource_specs"] = cloudbrain.ResourceSpecs.ResourceSpec ctx.Data["resource_specs"] = cloudbrain.ResourceSpecs.ResourceSpec

if cloudbrain.TrainResourceSpecs == nil {
json.Unmarshal([]byte(setting.TrainResourceSpecs), &cloudbrain.TrainResourceSpecs)
}
ctx.Data["train_resource_specs"] = cloudbrain.TrainResourceSpecs.ResourceSpec
ctx.Data["params"] = ""
ctx.Data["branchName"] = ctx.Repo.BranchName

ctx.Data["snn4imagenet_path"] = cloudbrain.Snn4imagenetMountPath ctx.Data["snn4imagenet_path"] = cloudbrain.Snn4imagenetMountPath
ctx.Data["is_snn4imagenet_enabled"] = setting.IsSnn4imagenetEnabled ctx.Data["is_snn4imagenet_enabled"] = setting.IsSnn4imagenetEnabled


@@ -184,38 +202,52 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) {
image := form.Image image := form.Image
uuid := form.Attachment uuid := form.Attachment
jobType := form.JobType jobType := form.JobType
command := cloudbrain.Command
gpuQueue := form.GpuType gpuQueue := form.GpuType
codePath := setting.JobPath + jobName + cloudbrain.CodeMountPath codePath := setting.JobPath + jobName + cloudbrain.CodeMountPath
resourceSpecId := form.ResourceSpecId resourceSpecId := form.ResourceSpecId
branchName := form.BranchName
repo := ctx.Repo.Repository repo := ctx.Repo.Repository


tasks, err := models.GetCloudbrainsByDisplayJobName(repo.ID, string(models.JobTypeDebug), displayJobName)
tpl := tplCloudBrainNew
command := cloudbrain.Command
if jobType == string(models.JobTypeTrain) {
tpl = tplCloudBrainTrainJobNew
commandTrain, err := getTrainJobCommand(form)
if err != nil {
log.Error("getTrainJobCommand failed: %v", err)
ctx.RenderWithErr(err.Error(), tpl, &form)
return
}

command = commandTrain
}

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


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


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


@@ -223,18 +255,21 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) {
if err != nil { if err != nil {
log.Error("GetCloudbrainCountByUserID failed:%v", err, ctx.Data["MsgID"]) log.Error("GetCloudbrainCountByUserID failed:%v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx) cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr("system error", tplCloudBrainNew, &form)
ctx.RenderWithErr("system error", tpl, &form)
return return
} else { } else {
if count >= 1 { if count >= 1 {
log.Error("the user already has running or waiting task", ctx.Data["MsgID"]) log.Error("the user already has running or waiting task", ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx) cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr("you have already a running or waiting task, can not create more", tplCloudBrainNew, &form)
ctx.RenderWithErr("you have already a running or waiting task, can not create more", tpl, &form)
return return
} }
} }


downloadCode(repo, codePath)
if branchName == "" {
branchName = cloudbrain.DefaultBranchName
}
downloadCode(repo, codePath, branchName)
uploadCodeToMinio(codePath+"/", jobName, cloudbrain.CodeMountPath+"/") uploadCodeToMinio(codePath+"/", jobName, cloudbrain.CodeMountPath+"/")


modelPath := setting.JobPath + jobName + cloudbrain.ModelMountPath + "/" modelPath := setting.JobPath + jobName + cloudbrain.ModelMountPath + "/"
@@ -268,15 +303,19 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) {
err = cloudbrain.GenerateTask(ctx, displayJobName, jobName, image, command, uuid, storage.GetMinioPath(jobName, cloudbrain.CodeMountPath+"/"), err = cloudbrain.GenerateTask(ctx, displayJobName, jobName, image, command, uuid, storage.GetMinioPath(jobName, cloudbrain.CodeMountPath+"/"),
storage.GetMinioPath(jobName, cloudbrain.ModelMountPath+"/"), storage.GetMinioPath(jobName, cloudbrain.ModelMountPath+"/"),
storage.GetMinioPath(jobName, cloudbrain.BenchMarkMountPath+"/"), storage.GetMinioPath(jobName, cloudbrain.Snn4imagenetMountPath+"/"), storage.GetMinioPath(jobName, cloudbrain.BenchMarkMountPath+"/"), storage.GetMinioPath(jobName, cloudbrain.Snn4imagenetMountPath+"/"),
storage.GetMinioPath(jobName, cloudbrain.BrainScoreMountPath+"/"), jobType, gpuQueue, form.Description,
storage.GetMinioPath(jobName, cloudbrain.BrainScoreMountPath+"/"), jobType, gpuQueue, form.Description, branchName, form.BootFile, form.Params,
0, 0, resourceSpecId) 0, 0, resourceSpecId)
if err != nil { if err != nil {
cloudBrainNewDataPrepare(ctx) cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr(err.Error(), tplCloudBrainNew, &form)
ctx.RenderWithErr(err.Error(), tpl, &form)
return return
} }


ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob?debugListType=all")
if jobType == string(models.JobTypeTrain) {
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/train-job?listType=all")
} else {
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob?debugListType=all")
}
} }


func CloudBrainRestart(ctx *context.Context) { func CloudBrainRestart(ctx *context.Context) {
@@ -307,6 +346,24 @@ func CloudBrainRestart(ctx *context.Context) {
break break
} }


var hasSameResource bool
if gpuInfos == nil {
json.Unmarshal([]byte(setting.GpuTypes), &gpuInfos)
}
for _, resourceType := range gpuInfos.GpuInfo {
if resourceType.Queue == task.GpuQueue {
hasSameResource = true
continue
}
}

if !hasSameResource {
log.Error("has no same resource, can not restart", ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "the job's version is too old and can not be restarted"
break
}

count, err := models.GetCloudbrainCountByUserID(ctx.User.ID, string(models.JobTypeDebug)) count, err := models.GetCloudbrainCountByUserID(ctx.User.ID, string(models.JobTypeDebug))
if err != nil { if err != nil {
log.Error("GetCloudbrainCountByUserID failed:%v", err, ctx.Data["MsgID"]) log.Error("GetCloudbrainCountByUserID failed:%v", err, ctx.Data["MsgID"])
@@ -342,32 +399,78 @@ func CloudBrainRestart(ctx *context.Context) {
} }


func CloudBrainBenchMarkShow(ctx *context.Context) { func CloudBrainBenchMarkShow(ctx *context.Context) {
cloudBrainShow(ctx, tplCloudBrainBenchmarkShow)
cloudBrainShow(ctx, tplCloudBrainBenchmarkShow, models.JobTypeBenchmark)
} }


func CloudBrainShow(ctx *context.Context) { func CloudBrainShow(ctx *context.Context) {
cloudBrainShow(ctx, tplCloudBrainShow)
cloudBrainShow(ctx, tplCloudBrainShow, models.JobTypeDebug)
}

func CloudBrainTrainJobShow(ctx *context.Context) {
cloudBrainShow(ctx, tplCloudBrainTrainJobShow, models.JobTypeTrain)
} }


func cloudBrainShow(ctx *context.Context, tpName base.TplName) {
func cloudBrainShow(ctx *context.Context, tpName base.TplName, jobType models.JobType) {
ctx.Data["PageIsCloudBrain"] = true ctx.Data["PageIsCloudBrain"] = true
var ID = ctx.Params(":id")
debugListType := ctx.Query("debugListType") debugListType := ctx.Query("debugListType")
task, err := models.GetCloudbrainByID(ID)

var task *models.Cloudbrain
var err error
if jobType == models.JobTypeTrain {
task, err = models.GetCloudbrainByJobID(ctx.Params(":jobid"))
} else {
task, err = models.GetCloudbrainByIDWithDeleted(ctx.Params(":id"))
}

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

result, err := cloudbrain.GetJob(task.JobID) result, err := cloudbrain.GetJob(task.JobID)
if err != nil { if err != nil {
log.Info("error:" + err.Error()) log.Info("error:" + err.Error())
ctx.Data["error"] = err.Error() ctx.Data["error"] = err.Error()
return
} }

if cloudbrain.ResourceSpecs == nil {
json.Unmarshal([]byte(setting.ResourceSpecs), &cloudbrain.ResourceSpecs)
}
for _, tmp := range cloudbrain.ResourceSpecs.ResourceSpec {
if tmp.Id == task.ResourceSpecId {
ctx.Data["GpuNum"] = tmp.GpuNum
ctx.Data["CpuNum"] = tmp.CpuNum
ctx.Data["MemMiB"] = tmp.MemMiB
ctx.Data["ShareMemMiB"] = tmp.ShareMemMiB
}
}

if result != nil { if result != nil {
jobRes, _ := models.ConvertToJobResultPayload(result.Payload) jobRes, _ := models.ConvertToJobResultPayload(result.Payload)
jobRes.Resource.Memory = strings.ReplaceAll(jobRes.Resource.Memory, "Mi", "MB") jobRes.Resource.Memory = strings.ReplaceAll(jobRes.Resource.Memory, "Mi", "MB")
spec := "GPU数:" + strconv.Itoa(jobRes.Resource.NvidiaComGpu) + ",CPU数:" + strconv.Itoa(jobRes.Resource.CPU) + ",内存(MB):" + jobRes.Resource.Memory spec := "GPU数:" + strconv.Itoa(jobRes.Resource.NvidiaComGpu) + ",CPU数:" + strconv.Itoa(jobRes.Resource.CPU) + ",内存(MB):" + jobRes.Resource.Memory
ctx.Data["resource_spec"] = spec ctx.Data["resource_spec"] = spec
if task.JobType == string(models.JobTypeTrain) {
if trainGpuInfos == nil {
json.Unmarshal([]byte(setting.TrainGpuTypes), &trainGpuInfos)
}
for _, resourceType := range trainGpuInfos.GpuInfo {
if resourceType.Queue == jobRes.Config.GpuType {
ctx.Data["resource_type"] = resourceType.Value
}
}
} else {
if gpuInfos == nil {
json.Unmarshal([]byte(setting.GpuTypes), &gpuInfos)
}
for _, resourceType := range gpuInfos.GpuInfo {
if resourceType.Queue == jobRes.Config.GpuType {
ctx.Data["resource_type"] = resourceType.Value
}
}
}
taskRoles := jobRes.TaskRoles taskRoles := jobRes.TaskRoles
if jobRes.JobStatus.State != string(models.JobFailed) { if jobRes.JobStatus.State != string(models.JobFailed) {


@@ -376,12 +479,16 @@ func cloudBrainShow(ctx *context.Context, tpName base.TplName) {
task.Status = taskRes.TaskStatuses[0].State task.Status = taskRes.TaskStatuses[0].State
task.ContainerID = taskRes.TaskStatuses[0].ContainerID task.ContainerID = taskRes.TaskStatuses[0].ContainerID
task.ContainerIp = taskRes.TaskStatuses[0].ContainerIP task.ContainerIp = taskRes.TaskStatuses[0].ContainerIP
if task.StartTime == 0 && !taskRes.TaskStatuses[0].StartAt.IsZero() {
task.StartTime = timeutil.TimeStamp(taskRes.TaskStatuses[0].StartAt.Unix())
}
err = models.UpdateJob(task)
if err != nil {
ctx.Data["error"] = err.Error()
models.ParseAndSetDurationFromCloudBrainOne(jobRes, task)

if task.DeletedAt.IsZero() { //normal record
err = models.UpdateJob(task)
if err != nil {
ctx.Data["error"] = err.Error()
return
}
} else { //deleted record

} }
} else { } else {
task.Status = jobRes.JobStatus.State task.Status = jobRes.JobStatus.State
@@ -398,7 +505,9 @@ func cloudBrainShow(ctx *context.Context, tpName base.TplName) {
ctx.Data["result"] = jobRes ctx.Data["result"] = jobRes
} else { } else {
log.Info("error:" + err.Error()) log.Info("error:" + err.Error())
return
} }

user, err := models.GetUserByID(task.UserID) user, err := models.GetUserByID(task.UserID)
if err == nil { if err == nil {
task.User = user task.User = user
@@ -419,15 +528,47 @@ func cloudBrainShow(ctx *context.Context, tpName base.TplName) {
} }
} }
if task.TrainJobDuration == "" { if task.TrainJobDuration == "" {
var duration int64
if task.Status == string(models.JobRunning) {
duration = time.Now().Unix() - int64(task.CreatedUnix)
} else {
duration = int64(task.UpdatedUnix) - int64(task.CreatedUnix)
if task.Duration == 0 {
var duration int64
if task.Status == string(models.JobRunning) {
duration = time.Now().Unix() - int64(task.CreatedUnix)
} else {
duration = int64(task.UpdatedUnix) - int64(task.CreatedUnix)
}
task.Duration = duration
} }
task.TrainJobDuration = models.ConvertDurationToStr(duration)
task.TrainJobDuration = models.ConvertDurationToStr(task.Duration)
} }
ctx.Data["duration"] = task.TrainJobDuration ctx.Data["duration"] = task.TrainJobDuration

if len(task.Parameters) > 0 {
var parameters models.Parameters

err := json.Unmarshal([]byte(task.Parameters), &parameters)
if err != nil {
log.Error("Failed to Unmarshal Parameters: %s (%v)", task.Parameters, err)
task.Parameters = ""
} else {
if len(parameters.Parameter) > 0 {
paramTemp := ""
for _, Parameter := range parameters.Parameter {
param := Parameter.Label + " = " + Parameter.Value + "; "
paramTemp = paramTemp + param
}
task.Parameters = paramTemp[:len(paramTemp)-2]
} else {
task.Parameters = ""
}
}

}
attachment, err := models.GetAttachmentByUUID(task.Uuid)
if err == nil {
ctx.Data["datasetname"] = attachment.Name
} else {
ctx.Data["datasetname"] = ""
}

ctx.Data["task"] = task ctx.Data["task"] = task
ctx.Data["jobName"] = task.JobName ctx.Data["jobName"] = task.JobName
ctx.Data["displayJobName"] = task.DisplayJobName ctx.Data["displayJobName"] = task.DisplayJobName
@@ -435,6 +576,10 @@ func cloudBrainShow(ctx *context.Context, tpName base.TplName) {
version_list_task = append(version_list_task, task) version_list_task = append(version_list_task, task)
ctx.Data["version_list_task"] = version_list_task ctx.Data["version_list_task"] = version_list_task
ctx.Data["debugListType"] = debugListType ctx.Data["debugListType"] = debugListType
ctx.Data["code_path"] = cloudbrain.CodeMountPath
ctx.Data["dataset_path"] = cloudbrain.DataSetMountPath
ctx.Data["model_path"] = cloudbrain.ModelMountPath
ctx.Data["canDownload"] = cloudbrain.CanModifyJob(ctx, task)
ctx.HTML(200, tpName) ctx.HTML(200, tpName)
} }


@@ -506,11 +651,12 @@ func CloudBrainStop(ctx *context.Context) {
break break
} }


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


@@ -762,8 +908,8 @@ func GetRate(ctx *context.Context) {
} }
} }


func downloadCode(repo *models.Repository, codePath string) error {
if err := git.Clone(repo.RepoPath(), codePath, git.CloneRepoOptions{}); err != nil {
func downloadCode(repo *models.Repository, codePath, branchName string) error {
if err := git.Clone(repo.RepoPath(), codePath, git.CloneRepoOptions{Branch: branchName}); err != nil {
log.Error("Failed to clone repository: %s (%v)", repo.FullName(), err) log.Error("Failed to clone repository: %s (%v)", repo.FullName(), err)
return err return err
} }
@@ -961,14 +1107,7 @@ func SyncCloudbrainStatus() {
taskRes, _ := models.ConvertToTaskPod(taskRoles[cloudbrain.SubTaskName].(map[string]interface{})) taskRes, _ := models.ConvertToTaskPod(taskRoles[cloudbrain.SubTaskName].(map[string]interface{}))
task.Status = taskRes.TaskStatuses[0].State task.Status = taskRes.TaskStatuses[0].State
if task.Status != string(models.JobWaiting) { if task.Status != string(models.JobWaiting) {
task.Duration = time.Now().Unix() - taskRes.TaskStatuses[0].StartAt.Unix()
if task.StartTime == 0 && !taskRes.TaskStatuses[0].StartAt.IsZero() {
task.StartTime = timeutil.TimeStamp(taskRes.TaskStatuses[0].StartAt.Unix())
}
if task.EndTime == 0 && models.IsCloudBrainOneDebugJobTerminal(task.Status) {
task.EndTime = timeutil.TimeStampNow()
}
task.ComputeAndSetDuration()
models.ParseAndSetDurationFromCloudBrainOne(jobRes, task)
err = models.UpdateJob(task) err = models.UpdateJob(task)
if err != nil { if err != nil {
log.Error("UpdateJob(%s) failed:%v", task.JobName, err) log.Error("UpdateJob(%s) failed:%v", task.JobName, err)
@@ -1011,8 +1150,8 @@ func SyncCloudbrainStatus() {


if result != nil { if result != nil {
task.Status = result.Status task.Status = result.Status
if task.StartTime == 0 && result.Lease.CreateTime > 0 {
task.StartTime = timeutil.TimeStamp(result.Lease.CreateTime / 1000)
if task.StartTime == 0 && result.Lease.UpdateTime > 0 {
task.StartTime = timeutil.TimeStamp(result.Lease.UpdateTime / 1000)
} }
if task.EndTime == 0 && models.IsModelArtsDebugJobTerminal(task.Status) { if task.EndTime == 0 && models.IsModelArtsDebugJobTerminal(task.Status) {
task.EndTime = timeutil.TimeStampNow() task.EndTime = timeutil.TimeStampNow()
@@ -1024,7 +1163,7 @@ func SyncCloudbrainStatus() {
continue continue
} }
} }
} else if task.JobType == string(models.JobTypeTrain) {
} else if task.JobType == string(models.JobTypeTrain) || task.JobType == string(models.JobTypeInference) {
result, err := modelarts.GetTrainJob(task.JobID, strconv.FormatInt(task.VersionID, 10)) result, err := modelarts.GetTrainJob(task.JobID, strconv.FormatInt(task.VersionID, 10))
if err != nil { if err != nil {
log.Error("GetTrainJob(%s) failed:%v", task.JobName, err) log.Error("GetTrainJob(%s) failed:%v", task.JobName, err)
@@ -1062,6 +1201,158 @@ func SyncCloudbrainStatus() {
return return
} }


func HandleTaskWithNoDuration(ctx *context.Context) {
log.Info("HandleTaskWithNoDuration start")
count := 0
start := time.Now().Unix()
for {
cloudBrains, err := models.GetStoppedJobWithNoDurationJob()
if err != nil {
log.Error("HandleTaskWithNoTrainJobDuration failed:", err.Error())
break
}
if len(cloudBrains) == 0 {
log.Info("HandleTaskWithNoTrainJobDuration:no task need handle")
break
}
handleNoDurationTask(cloudBrains)
count += len(cloudBrains)
if len(cloudBrains) < 100 {
log.Info("HandleTaskWithNoTrainJobDuration:task less than 100")
break
}
if time.Now().Unix()-start > 600 {
log.Info("HandleTaskWithNoDuration : time out")
ctx.JSON(200, fmt.Sprintf("task stop for time out,count=%d", count))
return
}
}
log.Info("HandleTaskWithNoTrainJobDuration:count=%d", count)
ctx.JSON(200, fmt.Sprintf("success,count=%d", count))
}

func handleNoDurationTask(cloudBrains []*models.Cloudbrain) {
for _, task := range cloudBrains {
time.Sleep(time.Millisecond * 100)
log.Info("Handle job ,%+v", task)
if task.Type == models.TypeCloudBrainOne {
result, err := cloudbrain.GetJob(task.JobID)
if err != nil {
log.Error("GetJob(%s) failed:%v", task.JobName, err)
updateDefaultDuration(task)
continue
}

if result != nil {
if result.Msg != "success" {
updateDefaultDuration(task)
continue
}
jobRes, err := models.ConvertToJobResultPayload(result.Payload)
if err != nil || len(jobRes.TaskRoles) == 0 {
updateDefaultDuration(task)
continue
}
taskRoles := jobRes.TaskRoles
taskRes, err := models.ConvertToTaskPod(taskRoles[cloudbrain.SubTaskName].(map[string]interface{}))
if err != nil || len(taskRes.TaskStatuses) == 0 {
updateDefaultDuration(task)
continue
}
task.Status = taskRes.TaskStatuses[0].State
log.Info("task startTime = %v endTime= %v ,jobId=%d", jobRes.JobStatus.StartTime, jobRes.JobStatus.EndTime, task.ID)
if jobRes.JobStatus.CreatedTime > 0 {
task.StartTime = timeutil.TimeStamp(jobRes.JobStatus.CreatedTime / 1000)
if jobRes.JobStatus.CompletedTime > 0 {
task.EndTime = timeutil.TimeStamp(jobRes.JobStatus.CompletedTime / 1000)
} else {
task.EndTime = task.UpdatedUnix
}
} else {
task.StartTime = 0
task.EndTime = 0
}

if task.EndTime < task.StartTime {
log.Info("endTime[%v] is less than starTime[%v],jobId=%d", task.EndTime, task.StartTime, task.ID)
st := task.StartTime
task.StartTime = task.EndTime
task.EndTime = st
}
task.Duration = task.EndTime.AsTime().Unix() - task.StartTime.AsTime().Unix()
task.TrainJobDuration = models.ConvertDurationToStr(task.Duration)
err = models.UpdateJob(task)
if err != nil {
log.Error("UpdateJob(%s) failed:%v", task.JobName, err)
}
}
} else if task.Type == models.TypeCloudBrainTwo {
if task.JobType == string(models.JobTypeDebug) {
//result, err := modelarts.GetJob(task.JobID)
result, err := modelarts.GetNotebook2(task.JobID)
if err != nil {
log.Error("GetJob(%s) failed:%v", task.JobName, err)
updateDefaultDuration(task)
continue
}

if result != nil {
task.Status = result.Status
startTime := result.Lease.CreateTime
duration := result.Lease.Duration / 1000
if startTime > 0 {
task.StartTime = timeutil.TimeStamp(startTime / 1000)
task.EndTime = task.StartTime.Add(duration)
}
task.ComputeAndSetDuration()
err = models.UpdateJob(task)
if err != nil {
log.Error("UpdateJob(%s) failed:%v", task.JobName, err)
continue
}
}
} else if task.JobType == string(models.JobTypeTrain) || task.JobType == string(models.JobTypeInference) {
result, err := modelarts.GetTrainJob(task.JobID, strconv.FormatInt(task.VersionID, 10))
if err != nil {
log.Error("GetTrainJob(%s) failed:%v", task.JobName, err)
updateDefaultDuration(task)
continue
}

if result != nil {
startTime := result.StartTime / 1000
if startTime > 0 {
task.StartTime = timeutil.TimeStamp(startTime)
task.EndTime = task.StartTime.Add(result.Duration / 1000)
}
task.ComputeAndSetDuration()
err = models.UpdateJob(task)
if err != nil {
log.Error("UpdateJob(%s) failed:%v", task.JobName, err)
continue
}
}
} else {
log.Error("task.JobType(%s) is error:%s", task.JobName, task.JobType)
}

} else {
log.Error("task.Type(%s) is error:%d", task.JobName, task.Type)
}
}
}

func updateDefaultDuration(task *models.Cloudbrain) {
log.Info("updateDefaultDuration: taskId=%d", task.ID)
task.StartTime = task.CreatedUnix
task.EndTime = task.UpdatedUnix
task.ComputeAndSetDuration()
err := models.UpdateJob(task)
if err != nil {
log.Error("UpdateJob(%s) failed:%v", task.JobName, err)
}
}

func CloudBrainBenchmarkIndex(ctx *context.Context) { func CloudBrainBenchmarkIndex(ctx *context.Context) {
MustEnableCloudbrain(ctx) MustEnableCloudbrain(ctx)
repo := ctx.Repo.Repository repo := ctx.Repo.Repository
@@ -1090,13 +1381,16 @@ func CloudBrainBenchmarkIndex(ctx *context.Context) {
ciTasks[i].CanDel = cloudbrain.CanDeleteJob(ctx, &task.Cloudbrain) ciTasks[i].CanDel = cloudbrain.CanDeleteJob(ctx, &task.Cloudbrain)
ciTasks[i].Cloudbrain.ComputeResource = task.ComputeResource ciTasks[i].Cloudbrain.ComputeResource = task.ComputeResource
if ciTasks[i].TrainJobDuration == "" { if ciTasks[i].TrainJobDuration == "" {
var duration int64
if task.Status == string(models.JobRunning) {
duration = time.Now().Unix() - int64(task.Cloudbrain.CreatedUnix)
} else {
duration = int64(task.Cloudbrain.UpdatedUnix) - int64(task.Cloudbrain.CreatedUnix)
if ciTasks[i].Duration == 0 {
var duration int64
if task.Status == string(models.JobRunning) {
duration = time.Now().Unix() - int64(task.Cloudbrain.CreatedUnix)
} else {
duration = int64(task.Cloudbrain.UpdatedUnix) - int64(task.Cloudbrain.CreatedUnix)
}
ciTasks[i].Duration = duration
} }
ciTasks[i].TrainJobDuration = models.ConvertDurationToStr(duration)
ciTasks[i].TrainJobDuration = models.ConvertDurationToStr(ciTasks[i].Duration)
} }


ciTasks[i].BenchmarkTypeName = "" ciTasks[i].BenchmarkTypeName = ""
@@ -1315,7 +1609,7 @@ func CloudBrainBenchmarkCreate(ctx *context.Context, form auth.CreateCloudBrainF
} }


os.RemoveAll(codePath) os.RemoveAll(codePath)
if err := downloadCode(repo, codePath); err != nil {
if err := downloadCode(repo, codePath, cloudbrain.DefaultBranchName); err != nil {
log.Error("downloadCode failed, %v", err, ctx.Data["MsgID"]) log.Error("downloadCode failed, %v", err, ctx.Data["MsgID"])
cloudBrainNewDataPrepare(ctx) cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr("system error", tplCloudBrainBenchmarkNew, &form) ctx.RenderWithErr("system error", tplCloudBrainBenchmarkNew, &form)
@@ -1380,7 +1674,7 @@ func CloudBrainBenchmarkCreate(ctx *context.Context, form auth.CreateCloudBrainF
err = cloudbrain.GenerateTask(ctx, displayJobName, jobName, image, command, childInfo.Attachment, storage.GetMinioPath(jobName, cloudbrain.CodeMountPath+"/"), err = cloudbrain.GenerateTask(ctx, displayJobName, jobName, image, command, childInfo.Attachment, storage.GetMinioPath(jobName, cloudbrain.CodeMountPath+"/"),
storage.GetMinioPath(jobName, cloudbrain.ModelMountPath+"/"), storage.GetMinioPath(jobName, cloudbrain.ModelMountPath+"/"),
storage.GetMinioPath(jobName, cloudbrain.BenchMarkMountPath+"/"), storage.GetMinioPath(jobName, cloudbrain.Snn4imagenetMountPath+"/"), storage.GetMinioPath(jobName, cloudbrain.BenchMarkMountPath+"/"), storage.GetMinioPath(jobName, cloudbrain.Snn4imagenetMountPath+"/"),
storage.GetMinioPath(jobName, cloudbrain.BrainScoreMountPath+"/"), string(models.JobTypeBenchmark), gpuQueue, form.Description,
storage.GetMinioPath(jobName, cloudbrain.BrainScoreMountPath+"/"), string(models.JobTypeBenchmark), gpuQueue, form.Description, cloudbrain.DefaultBranchName, "", "",
benchmarkTypeID, benchmarkChildTypeID, resourceSpecId) benchmarkTypeID, benchmarkChildTypeID, resourceSpecId)
if err != nil { if err != nil {
cloudBrainNewDataPrepare(ctx) cloudBrainNewDataPrepare(ctx)
@@ -1406,10 +1700,66 @@ func BenchmarkDel(ctx *context.Context) {
} }
} }


func CloudBrainTrainJobNew(ctx *context.Context) {
err := cloudBrainNewDataPrepare(ctx)
if err != nil {
ctx.ServerError("get new train-job info failed", err)
return
}
ctx.HTML(http.StatusOK, tplCloudBrainTrainJobNew)
}

func getTrainJobCommand(form auth.CreateCloudBrainForm) (string, error) {
var command string
bootFile := form.BootFile
params := form.Params

if !strings.HasSuffix(bootFile, ".py") {
log.Error("bootFile(%s) format error", bootFile)
return command, errors.New("bootFile format error")
}

var parameters models.Parameters
var param string
if len(params) != 0 {
err := json.Unmarshal([]byte(params), &parameters)
if err != nil {
log.Error("Failed to Unmarshal params: %s (%v)", params, err)
return command, err
}

for _, parameter := range parameters.Parameter {
param += " --" + parameter.Label + "=" + parameter.Value
}
}

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

return command, nil
}

func CloudBrainTrainJobDel(ctx *context.Context) {
var listType = ctx.Query("listType")
if err := deleteCloudbrainJob(ctx); err != nil {
log.Error("deleteCloudbrainJob failed: %v", err, ctx.Data["msgID"])
ctx.ServerError(err.Error(), err)
return
}

var isAdminPage = ctx.Query("isadminpage")
if ctx.IsUserSiteAdmin() && isAdminPage == "true" {
ctx.Redirect(setting.AppSubURL + "/admin" + "/cloudbrains")
} else {
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/train-job?listType=" + listType)
}
}

func GetBenchmarkTypes(ctx *context.Context) *models.BenchmarkTypes { func GetBenchmarkTypes(ctx *context.Context) *models.BenchmarkTypes {
var lang = ctx.Locale.Language() var lang = ctx.Locale.Language()
if benchmarkTypesMap[lang] == nil { if benchmarkTypesMap[lang] == nil {
var val = i18n.Tr(lang, BENCHMARK_TYPE_CODE) var val = i18n.Tr(lang, BENCHMARK_TYPE_CODE)
//use config
val = setting.BenchmarkTypes
var tempType *models.BenchmarkTypes var tempType *models.BenchmarkTypes
if err := json.Unmarshal([]byte(val), &tempType); err != nil { if err := json.Unmarshal([]byte(val), &tempType); err != nil {
log.Error("json.Unmarshal BenchmarkTypes(%s) failed:%v", val, err, ctx.Data["MsgID"]) log.Error("json.Unmarshal BenchmarkTypes(%s) failed:%v", val, err, ctx.Data["MsgID"])


+ 135
- 42
routers/repo/modelarts.go View File

@@ -2,9 +2,9 @@ package repo


import ( import (
"archive/zip" "archive/zip"
"code.gitea.io/gitea/modules/timeutil"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
@@ -15,6 +15,9 @@ import (
"time" "time"
"unicode/utf8" "unicode/utf8"


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

"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/auth" "code.gitea.io/gitea/modules/auth"
"code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/base"
@@ -47,20 +50,26 @@ const (
) )


func DebugJobIndex(ctx *context.Context) { func DebugJobIndex(ctx *context.Context) {
debugListType := ctx.Query("debugListType")
ctx.Data["ListType"] = debugListType
listType := ctx.Query("debugListType")
ctx.Data["ListType"] = listType
MustEnableCloudbrain(ctx) MustEnableCloudbrain(ctx)
repo := ctx.Repo.Repository repo := ctx.Repo.Repository
page := ctx.QueryInt("page") page := ctx.QueryInt("page")
if page <= 0 { if page <= 0 {
page = 1 page = 1
} }
debugType := modelarts.DebugType
typeCloudBrain := models.TypeCloudBrainAll
jobTypeNot := false jobTypeNot := false
if debugListType == models.GPUResource {
debugType = models.TypeCloudBrainOne
} else if debugListType == models.NPUResource {
debugType = models.TypeCloudBrainTwo
if listType == models.GPUResource {
typeCloudBrain = models.TypeCloudBrainOne
} else if listType == models.NPUResource {
typeCloudBrain = models.TypeCloudBrainTwo
} else if listType == models.AllResource {
typeCloudBrain = models.TypeCloudBrainAll
} else {
log.Error("listType(%s) error", listType)
ctx.ServerError("listType error", errors.New("listType error"))
return
} }


var jobTypes []string var jobTypes []string
@@ -71,7 +80,7 @@ func DebugJobIndex(ctx *context.Context) {
PageSize: setting.UI.IssuePagingNum, PageSize: setting.UI.IssuePagingNum,
}, },
RepoID: repo.ID, RepoID: repo.ID,
Type: debugType,
Type: typeCloudBrain,
JobTypeNot: jobTypeNot, JobTypeNot: jobTypeNot,
JobTypes: jobTypes, JobTypes: jobTypes,
}) })
@@ -93,7 +102,7 @@ func DebugJobIndex(ctx *context.Context) {
ctx.Data["Tasks"] = ciTasks ctx.Data["Tasks"] = ciTasks
ctx.Data["CanCreate"] = cloudbrain.CanCreateOrDebugJob(ctx) ctx.Data["CanCreate"] = cloudbrain.CanCreateOrDebugJob(ctx)
ctx.Data["RepoIsEmpty"] = repo.IsEmpty ctx.Data["RepoIsEmpty"] = repo.IsEmpty
ctx.Data["debugListType"] = debugListType
ctx.Data["debugListType"] = listType
ctx.HTML(200, tplDebugJobIndex) ctx.HTML(200, tplDebugJobIndex)
} }


@@ -240,7 +249,7 @@ func NotebookShow(ctx *context.Context) {
debugListType := ctx.Query("debugListType") debugListType := ctx.Query("debugListType")


var ID = ctx.Params(":id") var ID = ctx.Params(":id")
task, err := models.GetCloudbrainByID(ID)
task, err := models.GetCloudbrainByIDWithDeleted(ID)
if err != nil { if err != nil {
ctx.Data["error"] = err.Error() ctx.Data["error"] = err.Error()
ctx.RenderWithErr(err.Error(), tplModelArtsNotebookShow, nil) ctx.RenderWithErr(err.Error(), tplModelArtsNotebookShow, nil)
@@ -255,16 +264,19 @@ func NotebookShow(ctx *context.Context) {
} }


if result != nil { if result != nil {
task.Status = result.Status
err = models.UpdateJob(task)
if err != nil {
ctx.Data["error"] = err.Error()
ctx.RenderWithErr(err.Error(), tplModelArtsNotebookShow, nil)
return
}
if task.DeletedAt.IsZero() { //normal record
if task.Status != result.Status {
task.Status = result.Status
err = models.UpdateJob(task)
if err != nil {
ctx.Data["error"] = err.Error()
ctx.RenderWithErr(err.Error(), tplModelArtsNotebookShow, nil)
return
}
}
} else { //deleted record


result.CreateTime = time.Unix(int64(result.CreateAt/1000), 0).Format("2006-01-02 15:04:05")
result.LatestUpdateTime = time.Unix(int64(result.UpdateAt/1000), 0).Format("2006-01-02 15:04:05")
}
} }


datasetDownloadLink := "-" datasetDownloadLink := "-"
@@ -272,16 +284,44 @@ func NotebookShow(ctx *context.Context) {
if task.Uuid != "" && task.UserID == ctx.User.ID { if task.Uuid != "" && task.UserID == ctx.User.ID {
attachment, err := models.GetAttachmentByUUID(task.Uuid) attachment, err := models.GetAttachmentByUUID(task.Uuid)
if err == nil { if err == nil {
task.DatasetName = attachment.Name
datasetDownloadLink = attachment.S3DownloadURL() datasetDownloadLink = attachment.S3DownloadURL()
} }
} }
} }

user, err := models.GetUserByID(task.UserID)
if err == nil {
task.User = user
}
if modelarts.FlavorInfos == nil {
json.Unmarshal([]byte(setting.FlavorInfos), &modelarts.FlavorInfos)
}
if modelarts.FlavorInfos != nil {
ctx.Data["resource_spec"] = modelarts.FlavorInfos.FlavorInfo[0].Desc
for _, f := range modelarts.FlavorInfos.FlavorInfo {
if fmt.Sprint(f.Value) == task.FlavorCode {
ctx.Data["resource_spec"] = f.Desc
break
}
}
}
if task.TrainJobDuration == "" {
if task.Duration == 0 {
var duration int64
if task.Status == string(models.JobRunning) {
duration = time.Now().Unix() - int64(task.CreatedUnix)
} else {
duration = int64(task.UpdatedUnix) - int64(task.CreatedUnix)
}
task.Duration = duration
}
task.TrainJobDuration = models.ConvertDurationToStr(task.Duration)
}
ctx.Data["duration"] = task.TrainJobDuration
ctx.Data["datasetDownloadLink"] = datasetDownloadLink ctx.Data["datasetDownloadLink"] = datasetDownloadLink
ctx.Data["task"] = task ctx.Data["task"] = task
ctx.Data["ID"] = ID ctx.Data["ID"] = ID
ctx.Data["jobName"] = task.JobName ctx.Data["jobName"] = task.JobName
ctx.Data["result"] = result
ctx.Data["debugListType"] = debugListType ctx.Data["debugListType"] = debugListType
ctx.HTML(200, tplModelArtsNotebookShow) ctx.HTML(200, tplModelArtsNotebookShow)
} }
@@ -410,20 +450,46 @@ func NotebookManage(ctx *context.Context) {
break break
} }


task.Status = res.Status
if task.EndTime == 0 && models.IsModelArtsDebugJobTerminal(task.Status) {
task.EndTime = timeutil.TimeStampNow()
}
task.ComputeAndSetDuration()
err = models.UpdateJob(task)
if err != nil {
log.Error("UpdateJob(%s) failed:%v", task.JobName, err.Error(), ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "system error"
break
}
status = res.Status
if action == models.ActionStart {
newTask := &models.Cloudbrain{
Status: status,
UserID: task.UserID,
RepoID: task.RepoID,
JobID: task.JobID,
JobName: task.JobName,
DisplayJobName: task.DisplayJobName,
JobType: task.JobType,
Type: task.Type,
Uuid: task.Uuid,
Image: task.Image,
ComputeResource: task.ComputeResource,
Description: task.Description,
}


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


break break
} }
@@ -480,6 +546,26 @@ func TrainJobIndex(ctx *context.Context) {
page = 1 page = 1
} }


listType := ctx.Query("listType")
if len(listType) == 0 {
listType = models.AllResource
}
ctx.Data["ListType"] = listType

typeCloudBrain := models.TypeCloudBrainAll
if listType == models.GPUResource {
typeCloudBrain = models.TypeCloudBrainOne
} else if listType == models.NPUResource {
typeCloudBrain = models.TypeCloudBrainTwo
} else if listType == models.AllResource {
typeCloudBrain = models.TypeCloudBrainAll
}
//else {
// log.Error("listType(%s) error", listType)
// ctx.ServerError("listType error", errors.New("listType error"))
// return
//}

var jobTypes []string var jobTypes []string
jobTypes = append(jobTypes, string(models.JobTypeTrain)) jobTypes = append(jobTypes, string(models.JobTypeTrain))
tasks, count, err := models.Cloudbrains(&models.CloudbrainsOptions{ tasks, count, err := models.Cloudbrains(&models.CloudbrainsOptions{
@@ -488,7 +574,7 @@ func TrainJobIndex(ctx *context.Context) {
PageSize: setting.UI.IssuePagingNum, PageSize: setting.UI.IssuePagingNum,
}, },
RepoID: repo.ID, RepoID: repo.ID,
Type: models.TypeCloudBrainTwo,
Type: typeCloudBrain,
JobTypeNot: false, JobTypeNot: false,
JobTypes: jobTypes, JobTypes: jobTypes,
IsLatestVersion: modelarts.IsLatestVersion, IsLatestVersion: modelarts.IsLatestVersion,
@@ -501,11 +587,16 @@ func TrainJobIndex(ctx *context.Context) {
for i, task := range tasks { for i, task := range tasks {
tasks[i].CanDel = cloudbrain.CanDeleteJob(ctx, &task.Cloudbrain) tasks[i].CanDel = cloudbrain.CanDeleteJob(ctx, &task.Cloudbrain)
tasks[i].CanModify = cloudbrain.CanModifyJob(ctx, &task.Cloudbrain) tasks[i].CanModify = cloudbrain.CanModifyJob(ctx, &task.Cloudbrain)
tasks[i].ComputeResource = models.NPUResource
if task.Cloudbrain.Type == models.TypeCloudBrainOne {
tasks[i].ComputeResource = models.GPUResource
} else if task.Cloudbrain.Type == models.TypeCloudBrainTwo {
tasks[i].ComputeResource = models.NPUResource
}
} }


pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, 5) pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, 5)
pager.SetDefaultParams(ctx) pager.SetDefaultParams(ctx)
pager.AddParam(ctx, "listType", "ListType")
ctx.Data["Page"] = pager ctx.Data["Page"] = pager


ctx.Data["PageIsCloudBrain"] = true ctx.Data["PageIsCloudBrain"] = true
@@ -1495,7 +1586,7 @@ func TrainJobShow(ctx *context.Context) {
ctx.Data["displayJobName"] = VersionListTasks[0].DisplayJobName ctx.Data["displayJobName"] = VersionListTasks[0].DisplayJobName
ctx.Data["version_list_task"] = VersionListTasks ctx.Data["version_list_task"] = VersionListTasks
ctx.Data["version_list_count"] = VersionListCount ctx.Data["version_list_count"] = VersionListCount
ctx.Data["canDownload"] = cloudbrain.CanDeleteJob(ctx, &VersionListTasks[0].Cloudbrain)
ctx.Data["canDownload"] = cloudbrain.CanModifyJob(ctx, &VersionListTasks[0].Cloudbrain)
ctx.HTML(http.StatusOK, tplModelArtsTrainJobShow) ctx.HTML(http.StatusOK, tplModelArtsTrainJobShow)
} }


@@ -1555,6 +1646,7 @@ func trainJobGetLog(jobID string) (*models.GetTrainJobLogFileNamesResult, *model


func TrainJobDel(ctx *context.Context) { func TrainJobDel(ctx *context.Context) {
var jobID = ctx.Params(":jobid") var jobID = ctx.Params(":jobid")
var listType = ctx.Query("listType")
repo := ctx.Repo.Repository repo := ctx.Repo.Repository


var jobTypes []string var jobTypes []string
@@ -1596,12 +1688,13 @@ func TrainJobDel(ctx *context.Context) {
if ctx.IsUserSiteAdmin() && isAdminPage == "true" { if ctx.IsUserSiteAdmin() && isAdminPage == "true" {
ctx.Redirect(setting.AppSubURL + "/admin" + "/cloudbrains") ctx.Redirect(setting.AppSubURL + "/admin" + "/cloudbrains")
} else { } else {
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/train-job")
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/train-job?listType=" + listType)
} }
} }


func TrainJobStop(ctx *context.Context) { func TrainJobStop(ctx *context.Context) {
var jobID = ctx.Params(":jobid") var jobID = ctx.Params(":jobid")
var listType = ctx.Query("listType")
task := ctx.Cloudbrain task := ctx.Cloudbrain


_, err := modelarts.StopTrainJob(jobID, strconv.FormatInt(task.VersionID, 10)) _, err := modelarts.StopTrainJob(jobID, strconv.FormatInt(task.VersionID, 10))
@@ -1611,7 +1704,7 @@ func TrainJobStop(ctx *context.Context) {
return return
} }


ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/train-job")
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/train-job?listType=" + listType)
} }


func canUserCreateTrainJob(uid int64) (bool, error) { func canUserCreateTrainJob(uid int64) (bool, error) {
@@ -2124,7 +2217,7 @@ func InferenceJobShow(ctx *context.Context) {
ctx.Data["jobName"] = task.JobName ctx.Data["jobName"] = task.JobName
ctx.Data["displayJobName"] = task.DisplayJobName ctx.Data["displayJobName"] = task.DisplayJobName
ctx.Data["task"] = task ctx.Data["task"] = task
ctx.Data["canDownload"] = cloudbrain.CanDeleteJob(ctx, task)
ctx.Data["canDownload"] = cloudbrain.CanModifyJob(ctx, task)


tempUids := []int64{} tempUids := []int64{}
tempUids = append(tempUids, task.UserID) tempUids = append(tempUids, task.UserID)
@@ -2276,7 +2369,7 @@ func SetJobCount(ctx *context.Context) {
repoId := ctx.Repo.Repository.ID repoId := ctx.Repo.Repository.ID
_, jobCount, err := models.Cloudbrains(&models.CloudbrainsOptions{ _, jobCount, err := models.Cloudbrains(&models.CloudbrainsOptions{
RepoID: repoId, RepoID: repoId,
Type: modelarts.DebugType,
Type: models.TypeCloudBrainAll,
}) })
if err != nil { if err != nil {
ctx.ServerError("Get job faild:", err) ctx.ServerError("Get job faild:", err)


+ 49
- 5
routers/repo/user_data_analysis.go View File

@@ -54,7 +54,12 @@ func queryUserDataPage(ctx *context.Context, tableName string, queryObj interfac
"N1": ctx.Tr("user.static.createrepocount"), "N1": ctx.Tr("user.static.createrepocount"),
"O1": ctx.Tr("user.static.openiindex"), "O1": ctx.Tr("user.static.openiindex"),
"P1": ctx.Tr("user.static.registdate"), "P1": ctx.Tr("user.static.registdate"),
"Q1": ctx.Tr("user.static.countdate"),
"Q1": ctx.Tr("user.static.CloudBrainTaskNum"),
"R1": ctx.Tr("user.static.CloudBrainRunTime"),
"S1": ctx.Tr("user.static.CommitDatasetNum"),
"T1": ctx.Tr("user.static.CommitModelCount"),
"U1": ctx.Tr("user.static.UserIndex"),
"V1": ctx.Tr("user.static.countdate"),
} }
for k, v := range dataHeader { for k, v := range dataHeader {
//设置单元格的值 //设置单元格的值
@@ -89,8 +94,14 @@ func queryUserDataPage(ctx *context.Context, tableName string, queryObj interfac
formatTime := userRecord.RegistDate.Format("2006-01-02 15:04:05") formatTime := userRecord.RegistDate.Format("2006-01-02 15:04:05")
xlsx.SetCellValue(sheetName, "P"+rows, formatTime[0:len(formatTime)-3]) xlsx.SetCellValue(sheetName, "P"+rows, formatTime[0:len(formatTime)-3])


xlsx.SetCellValue(sheetName, "Q"+rows, userRecord.CloudBrainTaskNum)
xlsx.SetCellValue(sheetName, "R"+rows, fmt.Sprintf("%.2f", float64(userRecord.CloudBrainRunTime)/3600))
xlsx.SetCellValue(sheetName, "S"+rows, userRecord.CommitDatasetNum)
xlsx.SetCellValue(sheetName, "T"+rows, userRecord.CommitModelCount)
xlsx.SetCellValue(sheetName, "U"+rows, fmt.Sprintf("%.2f", userRecord.UserIndex))

formatTime = userRecord.DataDate formatTime = userRecord.DataDate
xlsx.SetCellValue(sheetName, "Q"+rows, formatTime)
xlsx.SetCellValue(sheetName, "V"+rows, formatTime)
} }


indexTotal += PAGE_SIZE indexTotal += PAGE_SIZE
@@ -115,6 +126,30 @@ func queryUserDataPage(ctx *context.Context, tableName string, queryObj interfac
} }
} }


func QueryMetrics(ctx *context.Context) {
startDate := ctx.Query("startDate")
endDate := ctx.Query("endDate")
startTime, _ := time.ParseInLocation("2006-01-02", startDate, time.Local)
endTime, _ := time.ParseInLocation("2006-01-02", endDate, time.Local)
result, count := models.QueryMetrics(startTime.Unix(), endTime.Unix())
mapInterface := make(map[string]interface{})
mapInterface["data"] = result
mapInterface["count"] = count
ctx.JSON(http.StatusOK, mapInterface)
}

func QueryRankingList(ctx *context.Context) {
key := ctx.Query("key")
tableName := ctx.Query("tableName")
limit := ctx.QueryInt("limit")

result, count := models.QueryRankList(key, tableName, limit)
mapInterface := make(map[string]interface{})
mapInterface["data"] = result
mapInterface["count"] = count
ctx.JSON(http.StatusOK, mapInterface)
}

func QueryUserStaticCurrentMonth(ctx *context.Context) { func QueryUserStaticCurrentMonth(ctx *context.Context) {
queryUserDataPage(ctx, "public.user_business_analysis_current_month", new(models.UserBusinessAnalysisCurrentMonth)) queryUserDataPage(ctx, "public.user_business_analysis_current_month", new(models.UserBusinessAnalysisCurrentMonth))
} }
@@ -221,7 +256,12 @@ func QueryUserStaticDataPage(ctx *context.Context) {
"N1": ctx.Tr("user.static.createrepocount"), "N1": ctx.Tr("user.static.createrepocount"),
"O1": ctx.Tr("user.static.openiindex"), "O1": ctx.Tr("user.static.openiindex"),
"P1": ctx.Tr("user.static.registdate"), "P1": ctx.Tr("user.static.registdate"),
"Q1": ctx.Tr("user.static.countdate"),
"Q1": ctx.Tr("user.static.CloudBrainTaskNum"),
"R1": ctx.Tr("user.static.CloudBrainRunTime"),
"S1": ctx.Tr("user.static.CommitDatasetNum"),
"T1": ctx.Tr("user.static.CommitModelCount"),
"U1": ctx.Tr("user.static.UserIndex"),
"V1": ctx.Tr("user.static.countdate"),
} }
for k, v := range dataHeader { for k, v := range dataHeader {
//设置单元格的值 //设置单元格的值
@@ -249,9 +289,13 @@ func QueryUserStaticDataPage(ctx *context.Context) {


formatTime := userRecord.RegistDate.Format("2006-01-02 15:04:05") formatTime := userRecord.RegistDate.Format("2006-01-02 15:04:05")
xlsx.SetCellValue(sheetName, "P"+rows, formatTime[0:len(formatTime)-3]) xlsx.SetCellValue(sheetName, "P"+rows, formatTime[0:len(formatTime)-3])

xlsx.SetCellValue(sheetName, "Q"+rows, userRecord.CloudBrainTaskNum)
xlsx.SetCellValue(sheetName, "R"+rows, fmt.Sprintf("%.2f", float64(userRecord.CloudBrainRunTime)/3600))
xlsx.SetCellValue(sheetName, "S"+rows, userRecord.CommitDatasetNum)
xlsx.SetCellValue(sheetName, "T"+rows, userRecord.CommitModelCount)
xlsx.SetCellValue(sheetName, "U"+rows, fmt.Sprintf("%.2f", userRecord.UserIndex))
formatTime = userRecord.DataDate formatTime = userRecord.DataDate
xlsx.SetCellValue(sheetName, "Q"+rows, formatTime+" 00:01")
xlsx.SetCellValue(sheetName, "V"+rows, formatTime)
} }


//设置默认打开的表单 //设置默认打开的表单


+ 14
- 10
routers/repo/view.go View File

@@ -247,7 +247,11 @@ func renderDirectory(ctx *context.Context, treeLink string) {
ctx.Data["ReadmeInList"] = true ctx.Data["ReadmeInList"] = true
ctx.Data["ReadmeExist"] = true ctx.Data["ReadmeExist"] = true
ctx.Data["FileIsSymlink"] = readmeFile.isSymlink ctx.Data["FileIsSymlink"] = readmeFile.isSymlink
ctx.Data["ReadmeName"] = readmeFile.name
if ctx.Repo.TreePath == "" {
ctx.Data["ReadmeRelativePath"] = readmeFile.name
} else {
ctx.Data["ReadmeRelativePath"] = ctx.Repo.TreePath + "/" + readmeFile.name
}


if ctx.Repo.CanEnableEditor() { if ctx.Repo.CanEnableEditor() {
ctx.Data["CanEditFile"] = true ctx.Data["CanEditFile"] = true
@@ -579,11 +583,11 @@ func safeURL(address string) string {
} }


type ContributorInfo struct { type ContributorInfo struct {
UserInfo *models.User // nil for contributor who is not a registered user
RelAvatarLink string `json:"rel_avatar_link"`
UserName string `json:"user_name"`
Email string `json:"email"`
CommitCnt int `json:"commit_cnt"`
UserInfo *models.User // nil for contributor who is not a registered user
RelAvatarLink string `json:"rel_avatar_link"`
UserName string `json:"user_name"`
Email string `json:"email"`
CommitCnt int `json:"commit_cnt"`
} }


type GetContributorsInfo struct { type GetContributorsInfo struct {
@@ -642,7 +646,7 @@ func Home(ctx *context.Context) {
existedContributorInfo.CommitCnt += c.CommitCnt existedContributorInfo.CommitCnt += c.CommitCnt
} else { } else {
var newContributor = &ContributorInfo{ var newContributor = &ContributorInfo{
user, "", "",c.Email, c.CommitCnt,
user, "", "", c.Email, c.CommitCnt,
} }
count++ count++
contributorInfos = append(contributorInfos, newContributor) contributorInfos = append(contributorInfos, newContributor)
@@ -839,7 +843,7 @@ func renderCode(ctx *context.Context) {
compareInfo, err = baseGitRepo.GetCompareInfo(ctx.Repo.Repository.RepoPath(), ctx.Repo.BranchName, ctx.Repo.Repository.BaseRepo.DefaultBranch) compareInfo, err = baseGitRepo.GetCompareInfo(ctx.Repo.Repository.RepoPath(), ctx.Repo.BranchName, ctx.Repo.Repository.BaseRepo.DefaultBranch)
ctx.Data["UpstreamSameBranchName"] = false ctx.Data["UpstreamSameBranchName"] = false
} }
if err==nil && compareInfo != nil {
if err == nil && compareInfo != nil {
if compareInfo.Commits != nil { if compareInfo.Commits != nil {
log.Info("compareInfoCommits数量:%d", compareInfo.Commits.Len()) log.Info("compareInfoCommits数量:%d", compareInfo.Commits.Len())
ctx.Data["FetchUpstreamCnt"] = compareInfo.Commits.Len() ctx.Data["FetchUpstreamCnt"] = compareInfo.Commits.Len()
@@ -950,7 +954,7 @@ func ContributorsAPI(ctx *context.Context) {
} else { } else {
// new committer info // new committer info
var newContributor = &ContributorInfo{ var newContributor = &ContributorInfo{
user, user.RelAvatarLink(),user.Name, user.Email,c.CommitCnt,
user, user.RelAvatarLink(), user.Name, user.Email, c.CommitCnt,
} }
count++ count++
contributorInfos = append(contributorInfos, newContributor) contributorInfos = append(contributorInfos, newContributor)
@@ -963,7 +967,7 @@ func ContributorsAPI(ctx *context.Context) {
existedContributorInfo.CommitCnt += c.CommitCnt existedContributorInfo.CommitCnt += c.CommitCnt
} else { } else {
var newContributor = &ContributorInfo{ var newContributor = &ContributorInfo{
user, "", "",c.Email,c.CommitCnt,
user, "", "", c.Email, c.CommitCnt,
} }
count++ count++
contributorInfos = append(contributorInfos, newContributor) contributorInfos = append(contributorInfos, newContributor)


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

@@ -323,6 +323,9 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Get("/action/notification", routers.ActionNotification) m.Get("/action/notification", routers.ActionNotification)
m.Get("/recommend/org", routers.RecommendOrgFromPromote) m.Get("/recommend/org", routers.RecommendOrgFromPromote)
m.Get("/recommend/repo", routers.RecommendRepoFromPromote) m.Get("/recommend/repo", routers.RecommendRepoFromPromote)
m.Post("/all/search/", routers.Search)
m.Get("/all/search/", routers.EmptySearch)
m.Get("/all/dosearch/", routers.SearchApi)
m.Get("/home/term", routers.HomeTerm) m.Get("/home/term", routers.HomeTerm)
m.Group("/explore", func() { m.Group("/explore", func() {
m.Get("", func(ctx *context.Context) { m.Get("", func(ctx *context.Context) {
@@ -1035,6 +1038,19 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Post("/create", reqWechatBind, reqRepoCloudBrainWriter, bindIgnErr(auth.CreateCloudBrainForm{}), repo.CloudBrainBenchmarkCreate) m.Post("/create", reqWechatBind, reqRepoCloudBrainWriter, bindIgnErr(auth.CreateCloudBrainForm{}), repo.CloudBrainBenchmarkCreate)
m.Get("/get_child_types", repo.GetChildTypes) m.Get("/get_child_types", repo.GetChildTypes)
}) })

m.Group("/train-job", func() {
m.Group("/:jobid", func() {
m.Get("", reqRepoCloudBrainReader, repo.CloudBrainTrainJobShow)
m.Post("/del", cloudbrain.AdminOrOwnerOrJobCreaterRightForTrain, repo.CloudBrainTrainJobDel)
//m.Get("/models", reqRepoCloudBrainReader, repo.CloudBrainShowModels)
m.Get("/download_model", cloudbrain.AdminOrOwnerOrJobCreaterRightForTrain, repo.CloudBrainDownloadModel)
//m.Get("/create_version", reqWechatBind, cloudbrain.AdminOrJobCreaterRightForTrain, repo.TrainJobNewVersion)
//m.Post("/create_version", reqWechatBind, cloudbrain.AdminOrJobCreaterRightForTrain, bindIgnErr(auth.CreateModelArtsTrainJobForm{}), repo.TrainJobCreateVersion)
})
m.Get("/create", reqWechatBind, reqRepoCloudBrainWriter, repo.CloudBrainTrainJobNew)
m.Post("/create", reqWechatBind, reqRepoCloudBrainWriter, bindIgnErr(auth.CreateCloudBrainForm{}), repo.CloudBrainCreate)
})
}, context.RepoRef()) }, context.RepoRef())
m.Group("/modelmanage", func() { m.Group("/modelmanage", func() {
m.Post("/create_model", reqRepoModelManageWriter, repo.SaveModel) m.Post("/create_model", reqRepoModelManageWriter, repo.SaveModel)


+ 1194
- 0
routers/search.go
File diff suppressed because it is too large
View File


+ 1
- 1
services/socketwrap/clientManager.go View File

@@ -10,7 +10,7 @@ import (
"github.com/elliotchance/orderedmap" "github.com/elliotchance/orderedmap"
) )


var opTypes = []int{1, 2, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 17, 22, 23, 25, 26, 27, 28, 29, 30}
var opTypes = []int{1, 2, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 17, 22, 23, 25, 26, 27, 28, 29, 30, 31}


type ClientsManager struct { type ClientsManager struct {
Clients *orderedmap.OrderedMap Clients *orderedmap.OrderedMap


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

@@ -81,7 +81,7 @@
<span class="fitted" style="width: 90%;vertical-align: middle;">{{.DisplayJobName}}</span> <span class="fitted" style="width: 90%;vertical-align: middle;">{{.DisplayJobName}}</span>
</a> </a>
{{else if eq .JobType "TRAIN"}} {{else if eq .JobType "TRAIN"}}
<a class="title" href="{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}/modelarts/train-job/{{$JobID}}" title="{{.DisplayJobName}}" style="font-size: 14px;">
<a class="title" href="{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}{{if eq .ComputeResource "CPU/GPU"}}/cloudbrain{{else}}/modelarts{{end}}/train-job/{{$JobID}}" title="{{.DisplayJobName}}" style="font-size: 14px;">
<span class="fitted" style="width: 90%;vertical-align: middle;">{{.DisplayJobName}}</span> <span class="fitted" style="width: 90%;vertical-align: middle;">{{.DisplayJobName}}</span>
</a> </a>
{{else if eq .JobType "BENCHMARK"}} {{else if eq .JobType "BENCHMARK"}}
@@ -155,13 +155,13 @@
</a> </a>
</form> </form>
{{else}} {{else}}
<a style="padding: 0.5rem 1rem;" id="ai-stop-{{$JobID}}" class="ui basic ai_stop_version {{if eq .Status "KILLED" "FAILED" "START_FAILED" "KILLING" "COMPLETED"}}disabled {{else}} blue {{end}}button" data-repopath="{{.Repo.OwnerName}}/{{.Repo.Name}}/modelarts/{{if eq .JobType "INFERENCE"}}inference-job{{else}}train-job{{end}}" data-jobid="{{$JobID}}" data-version="{{.VersionName}}" >
<a style="padding: 0.5rem 1rem;" id="ai-stop-{{$JobID}}" class="ui basic ai_stop_version {{if eq .Status "KILLED" "FAILED" "START_FAILED" "KILLING" "COMPLETED" "SUCCEEDED" "STOPPED"}}disabled {{else}} blue {{end}}button" data-repopath="{{.Repo.OwnerName}}/{{.Repo.Name}}{{if eq .ComputeResource "CPU/GPU"}}/cloudbrain/train-job{{else}}/modelarts/{{if eq .JobType "INFERENCE"}}inference-job{{else}}train-job{{end}}{{end}}" data-jobid="{{$JobID}}" data-version="{{.VersionName}}" >
{{$.i18n.Tr "repo.stop"}} {{$.i18n.Tr "repo.stop"}}
</a> </a>
{{end}} {{end}}
</div> </div>
<!-- 删除任务 --> <!-- 删除任务 -->
<form class="ui compact buttons" id="delForm-{{$JobID}}" action='{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}{{if eq .JobType "BENCHMARK"}}/cloudbrain/benchmark{{else if eq .JobType "DEBUG"}}{{if eq .ComputeResource "NPU"}}/modelarts/notebook{{else}}/cloudbrain{{end}}{{else if eq .JobType "TRAIN"}}/modelarts/train-job{{end}}/{{$JobID}}/del?isadminpage=true' method="post">
<form class="ui compact buttons" id="delForm-{{$JobID}}" action='{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}{{if eq .JobType "BENCHMARK"}}/cloudbrain/benchmark{{else if eq .JobType "DEBUG"}}{{if eq .ComputeResource "NPU"}}/modelarts/notebook{{else}}/cloudbrain{{end}}{{else if eq .JobType "TRAIN"}}{{if eq .ComputeResource "NPU"}}/modelarts/notebook{{else}}/cloudbrain{{end}}/train-job{{end}}/{{$JobID}}/del?isadminpage=true' method="post">
{{$.CsrfTokenHtml}} {{$.CsrfTokenHtml}}
<a style="padding: 0.5rem 1rem;margin-left:0.2rem" id="ai-delete-{{$JobID}}" data-repopath="{{.Repo.OwnerName}}/{{.Repo.Name}}/modelarts/inference-job/{{$JobID}}/del_version?isadminpage=true" data-version="{{.VersionName}}" class="ui basic ai_delete blue button" style="border-radius: .28571429rem;"> <a style="padding: 0.5rem 1rem;margin-left:0.2rem" id="ai-delete-{{$JobID}}" data-repopath="{{.Repo.OwnerName}}/{{.Repo.Name}}/modelarts/inference-job/{{$JobID}}/del_version?isadminpage=true" data-version="{{.VersionName}}" class="ui basic ai_delete blue button" style="border-radius: .28571429rem;">
{{$.i18n.Tr "repo.delete"}} {{$.i18n.Tr "repo.delete"}}


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

@@ -95,9 +95,9 @@


{{if .IsSigned}} {{if .IsSigned}}
<div class="right stackable menu"> <div class="right stackable menu">
<form class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/explore/repos">
<form id="searchForm" class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/all/search/" method="post">
<div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;"> <div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;">
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search_pro"}}..."
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search"}}..."
style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;"> style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;">
<input type="hidden" name="tab" value="{{$.TabName}}"> <input type="hidden" name="tab" value="{{$.TabName}}">
<input type="hidden" name="sort" value="hot"> <input type="hidden" name="sort" value="hot">
@@ -199,9 +199,9 @@
<!--a class="item" target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io">{{.i18n.Tr "help"}}</a--> <!--a class="item" target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io">{{.i18n.Tr "help"}}</a-->
<div class="right stackable menu"> <div class="right stackable menu">
<form class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/explore/repos">
<form id="searchForm" class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/all/search/" method="post">
<div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;"> <div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;">
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search_pro"}}..."
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search"}}..."
style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;"> style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;">
<input type="hidden" name="tab" value="{{$.TabName}}"> <input type="hidden" name="tab" value="{{$.TabName}}">
<input type="hidden" name="sort" value="hot"> <input type="hidden" name="sort" value="hot">


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

@@ -93,9 +93,9 @@


{{if .IsSigned}} {{if .IsSigned}}
<div class="right stackable menu"> <div class="right stackable menu">
<form class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/explore/repos">
<form id="searchForm" class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/all/search/" method="post">
<div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;"> <div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;">
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search_pro"}}..."
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search"}}..."
style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;"> style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;">
<input type="hidden" name="tab" value="{{$.TabName}}"> <input type="hidden" name="tab" value="{{$.TabName}}">
<input type="hidden" name="sort" value="{{$.SortType}}"> <input type="hidden" name="sort" value="{{$.SortType}}">
@@ -196,9 +196,9 @@


<!--a class="item" target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io">{{.i18n.Tr "help"}}</a--> <!--a class="item" target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io">{{.i18n.Tr "help"}}</a-->
<div class="right stackable menu"> <div class="right stackable menu">
<form class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/explore/repos">
<form id="searchForm" class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/all/search/" method="post">
<div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;"> <div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;">
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search_pro"}}..."
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search"}}..."
style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;"> style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;">
<input type="hidden" name="tab" value="{{$.TabName}}"> <input type="hidden" name="tab" value="{{$.TabName}}">
<input type="hidden" name="sort" value="{{$.SortType}}"> <input type="hidden" name="sort" value="{{$.SortType}}">


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

@@ -96,9 +96,9 @@


{{if .IsSigned}} {{if .IsSigned}}
<div class="right stackable menu"> <div class="right stackable menu">
<form class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/explore/repos">
<form id="searchForm" class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/all/search/" method="post">
<div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;"> <div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;">
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search_pro"}}..."
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search"}}..."
style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;"> style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;">
<input type="hidden" name="tab" value="{{$.TabName}}"> <input type="hidden" name="tab" value="{{$.TabName}}">
<input type="hidden" name="sort" value="{{$.SortType}}"> <input type="hidden" name="sort" value="{{$.SortType}}">
@@ -199,9 +199,9 @@


<!--a class="item" target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io">{{.i18n.Tr "help"}}</a--> <!--a class="item" target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io">{{.i18n.Tr "help"}}</a-->
<div class="right stackable menu"> <div class="right stackable menu">
<form class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/explore/repos">
<form id="searchForm" class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/all/search/" method="post">
<div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;"> <div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;">
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search_pro"}}..."
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search"}}..."
style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;"> style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;">
<input type="hidden" name="tab" value="{{$.TabName}}"> <input type="hidden" name="tab" value="{{$.TabName}}">
<input type="hidden" name="sort" value="{{$.SortType}}"> <input type="hidden" name="sort" value="{{$.SortType}}">


+ 6
- 2
templates/custom/select_dataset.tmpl View File

@@ -3,7 +3,11 @@
<div class="inline {{if eq .cloudbraintype 0}} required {{end}} field" id="dataset-base"> <div class="inline {{if eq .cloudbraintype 0}} required {{end}} field" id="dataset-base">
<label>{{.i18n.Tr "dataset.dataset"}}</label> <label>{{.i18n.Tr "dataset.dataset"}}</label>
<input type="hidden" name="attachment" :value="dataset_uuid"> <input type="hidden" name="attachment" :value="dataset_uuid">
<input type="text" :value="dataset_name" disabled>
{{if eq .cloudbraintype 0}}
<input class="disabled" type="text" :value="dataset_name" required onfocus="this.blur();">
{{else}}
<input class="disabled" type="text" :value="dataset_name">
{{end}}
<el-button type="text" @click="dialogVisible = true" icon="el-icon-plus"> {{.i18n.Tr "dataset.select_dataset"}}</el-button> <el-button type="text" @click="dialogVisible = true" icon="el-icon-plus"> {{.i18n.Tr "dataset.select_dataset"}}</el-button>
<el-dialog <el-dialog
title="{{.i18n.Tr "dataset.select_dataset"}}" title="{{.i18n.Tr "dataset.select_dataset"}}"
@@ -131,4 +135,4 @@
</el-dialog> </el-dialog>




</div>
</div>

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

@@ -0,0 +1,134 @@

<div class="dataset-repolink" id="dataset-repolink-init" style="display: none;" data-repolink="{{.RepoLink}}" data-cloudranin-type="{{.cloudbraintype}}"></div>
<div class="inline required unite min_title field" id="dataset-base" style="margin-bottom: 0 !important;">
<label style="font-weight: normal;">{{.i18n.Tr "dataset.dataset"}}</label>&nbsp;&nbsp;&nbsp;
<input type="hidden" name="attachment" :value="dataset_uuid">
<input class="disabled" type="text" :value="dataset_name" required onfocus="this.blur();" style="width: 35.5%;">
<el-button type="text" @click="dialogVisible = true" icon="el-icon-plus" style="color: #0366d6;"> {{.i18n.Tr "dataset.select_dataset"}}</el-button>
<el-dialog
title="{{.i18n.Tr "dataset.select_dataset"}}"
:visible.sync="dialogVisible"
width="50%"
>
<div class="ui icon input" style="z-index: 9999;position: absolute;right: 50px;height:30px;">
<i class="search icon" style="cursor: pointer;pointer-events:auto" @click="searchDataset()"></i>
<input type="text" placeholder="{{.i18n.Tr "dataset.search_dataset"}}" v-model="searchDataItem" @keyup.enter="searchDataset()">
</div>
<el-tabs v-model="activeName" @tab-click="handleClick('{{.RepoLink}}',activeName,{{.cloudbraintype}})">
<el-tab-pane label="{{.i18n.Tr "dataset.current_project"}}" name="first">
<div style="display: flex;align-items: center;justify-content: space-between;padding: 1rem 0;border-bottom:1px solid #F5F5F5" v-for="(dataset,index) in currentRepoDataset" :key="index">
<div style="width: 90%;">
<div style="display: flex;align-items: center;"><span class="panel_creator_reponam">${dataset.Repo.OwnerName}/${dataset.Repo.Alias} </span><span class="panel_dataset_name">${dataset.Name} </span></div>
<div style="margin-top: 8px;display: flex;">
<a :title="dataset.UserName" style="cursor: default;">
<img class="ui avatar mini image" style="width: 20px;height: 20px;" :src="dataset.RelAvatarLink">
</a>
<span class="panel_datset_desc">${dataset.Description}</span>
</div>
</div>
<div>
<button v-if="dataset.DecompressState===1" class="ui primary basic button mini" @click.stop.prevent="selectDataset(dataset.UUID,dataset.Name)">{{.i18n.Tr "dataset.use"}}</button>
<span v-if="dataset.DecompressState===2" style="display: flex;align-items: center;">
<i class="CREATING"></i>
<span style="margin-left: 0.4em;font-size: 12px;color: #5A5A5A;" data-tooltip="{{$.i18n.Tr "dataset.unzip_tooltips"}}" data-inverted="" data-variation="mini" data-position="left center">解压中</span>
</span>
<span v-if="dataset.DecompressState===3" style="display: flex;align-items: center;">
<i class="FAILED"></i>
<span style="margin-left: 0.4em;font-size: 12px;color:red;" data-tooltip="{{$.i18n.Tr "dataset.zip_failed"}}" data-inverted="" data-variation="mini" data-position="left center">解压失败</span>
</span>
</div>
</div>
</el-tab-pane>
<el-tab-pane label="{{.i18n.Tr "dataset.owner_dataset"}}" name="second">
<div style="display: flex;align-items: center;justify-content: space-between;padding: 1rem 0;border-bottom:1px solid #F5F5F5" v-for="(dataset,index) in myDataset" :key="index">
<div style="width: 90%;">
<div style="display: flex;align-items: center;"><span class="panel_creator_reponam">${dataset.Repo.OwnerName}/${dataset.Repo.Alias}</span><span class="panel_dataset_name">${dataset.Name}</span></div>
<div style="margin-top: 8px;display: flex;">
<a :title="dataset.UserName" style="cursor: default;">
<img class="ui avatar mini image" style="width: 20px;height: 20px;" :src="dataset.RelAvatarLink">
</a>
<span class="panel_datset_desc">${dataset.Description}</span>
</div>
</div>
<div>
<button v-if="dataset.DecompressState===1" class="ui primary basic button mini" @click.stop.prevent="selectDataset(dataset.UUID,dataset.Name)">{{.i18n.Tr "dataset.use"}}</button>
<span v-if="dataset.DecompressState===2" style="display: flex;align-items: center;">
<i class="CREATING"></i>
<span style="margin-left: 0.4em;font-size: 12px;color: #5A5A5A;" data-tooltip="{{$.i18n.Tr "dataset.unzip_tooltips"}}" data-inverted="" data-variation="mini" data-position="left center">解压中</span>
</span>
<span v-if="dataset.DecompressState===3" style="display: flex;align-items: center;">
<i class="FAILED"></i>
<span style="margin-left: 0.4em;font-size: 12px;color:red;" data-tooltip="{{$.i18n.Tr "dataset.zip_failed"}}" data-inverted="" data-variation="mini" data-position="left center">解压失败</span>
</span>
</div>
</div>

</el-tab-pane>
<el-tab-pane label="{{.i18n.Tr "dataset.public_dataset"}}" name="third">
<div style="display: flex;align-items: center;justify-content: space-between;padding: 1rem 0;border-bottom:1px solid #F5F5F5" v-for="(dataset,index) in publicDataset" :key="index">
<div style="width: 90%;">
<div style="display: flex;align-items: center;"><span class="panel_creator_reponam">${dataset.Repo.OwnerName}/${dataset.Repo.Alias}</span><span class="panel_dataset_name">${dataset.Name}</span></div>
<div style="margin-top: 8px;display: flex;">
<a :title="dataset.UserName" style="cursor: default;">
<img class="ui avatar mini image" style="width: 20px;height: 20px;" :src="dataset.RelAvatarLink">
</a>
<span class="panel_datset_desc">${dataset.Description}</span>
</div>
</div>
<div>
<button v-if="dataset.DecompressState===1" class="ui primary basic button mini" @click.stop.prevent="selectDataset(dataset.UUID,dataset.Name)">{{.i18n.Tr "dataset.use"}}</button>
<span v-if="dataset.DecompressState===2" style="display: flex;align-items: center;">
<i class="CREATING"></i>
<span style="margin-left: 0.4em;font-size: 12px;color: #5A5A5A;" data-tooltip="{{$.i18n.Tr "dataset.unzip_tooltips"}}" data-inverted="" data-variation="mini" data-position="left center">解压中</span>
</span>
<span v-if="dataset.DecompressState===3" style="display: flex;align-items: center;">
<i class="FAILED"></i>
<span style="margin-left: 0.4em;font-size: 12px;color:red;" data-tooltip="{{$.i18n.Tr "dataset.zip_failed"}}" data-inverted="" data-variation="mini" data-position="left center">解压失败</span>
</span>
</div>
</div>

</el-tab-pane>
<el-tab-pane label="{{.i18n.Tr "dataset.I_liked"}}" name="fourth">
<div style="display: flex;align-items: center;justify-content: space-between;padding: 1rem 0;border-bottom:1px solid #F5F5F5" v-for="(dataset,index) in myFavoriteDataset" :key="index">
<div style="width: 90%;">
<div style="display: flex;align-items: center;"><span class="panel_creator_reponam">${dataset.Repo.OwnerName}/${dataset.Repo.Alias}</span><span class="panel_dataset_name">${dataset.Name}</span></div>
<div style="margin-top: 8px;display: flex;">
<a :title="dataset.UserName" style="cursor: default;">
<img class="ui avatar mini image" style="width: 20px;height: 20px;" :src="dataset.RelAvatarLink">
</a>
<span class="panel_datset_desc">${dataset.Description}</span>
</div>
</div>
<div>
<button v-if="dataset.DecompressState===1" class="ui primary basic button mini" @click.stop.prevent="selectDataset(dataset.UUID,dataset.Name)">{{.i18n.Tr "dataset.use"}}</button>
<span v-if="dataset.DecompressState===2" style="display: flex;align-items: center;">
<i class="CREATING"></i>
<span style="margin-left: 0.4em;font-size: 12px;color: #5A5A5A;" data-tooltip="{{$.i18n.Tr "dataset.unzip_tooltips"}}" data-inverted="" data-variation="mini" data-position="left center">解压中</span>
</span>
<span v-if="dataset.DecompressState===3" style="display: flex;align-items: center;">
<i class="FAILED"></i>
<span style="margin-left: 0.4em;font-size: 12px;color:red;" data-tooltip="{{$.i18n.Tr "dataset.zip_failed"}}" data-inverted="" data-variation="mini" data-position="left center">解压失败</span>
</span>
</div>
</div>

</el-tab-pane>
</el-tabs>
<div class="center">
<el-pagination
background
@current-change="handleCurrentChange"
:current-page="page"
:page-size="5"
layout="total,prev, pager, next"
:total="totalnums">
</el-pagination>
</div>
</el-dialog>


</div>

+ 11
- 5
templates/explore/datasets.tmpl View File

@@ -121,10 +121,10 @@
<i class="dropdown icon"></i> <i class="dropdown icon"></i>
</span> </span>
<div class="menu"> <div class="menu">
<a class="{{if eq .SortType "newest"}}active{{end}} item" href="{{$.Link}}?sort=newest&q={{$.Keyword}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.latest"}}</a>
<a class="{{if eq .SortType "oldest"}}active{{end}} item" href="{{$.Link}}?sort=oldest&q={{$.Keyword}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.oldest"}}</a>
<a class="{{if eq .SortType "recentupdate"}}active{{end}} item" href="{{$.Link}}?sort=recentupdate&q={{$.Keyword}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.recentupdate"}}</a>
<a class="{{if eq .SortType "leastupdate"}}active{{end}} item" href="{{$.Link}}?sort=leastupdate&q={{$.Keyword}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.leastupdate"}}</a>
<a class="{{if eq .SortType "newest"}}active{{end}} item" href="{{$.Link}}?sort=newest&q={{$.Keyword}}&tab={{$.TabName}}&category={{$.Category}}&task={{$.Task}}&license={{$.License}}">{{.i18n.Tr "repo.issues.filter_sort.latest"}}</a>
<a class="{{if eq .SortType "oldest"}}active{{end}} item" href="{{$.Link}}?sort=oldest&q={{$.Keyword}}&tab={{$.TabName}}&category={{$.Category}}&task={{$.Task}}&license={{$.License}}">{{.i18n.Tr "repo.issues.filter_sort.oldest"}}</a>
<a class="{{if eq .SortType "recentupdate"}}active{{end}} item" href="{{$.Link}}?sort=recentupdate&q={{$.Keyword}}&tab={{$.TabName}}&category={{$.Category}}&task={{$.Task}}&license={{$.License}}">{{.i18n.Tr "repo.issues.filter_sort.recentupdate"}}</a>
<a class="{{if eq .SortType "leastupdate"}}active{{end}} item" href="{{$.Link}}?sort=leastupdate&q={{$.Keyword}}&tab={{$.TabName}}&category={{$.Category}}&task={{$.Task}}&license={{$.License}}">{{.i18n.Tr "repo.issues.filter_sort.leastupdate"}}</a>
<!-- <a class="{{if eq .SortType "downloadtimes"}}active{{end}} item" href="{{$.Link}}?sort=downloadtimes&q={{$.Keyword}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.downloadtimes"}}</a> --> <!-- <a class="{{if eq .SortType "downloadtimes"}}active{{end}} item" href="{{$.Link}}?sort=downloadtimes&q={{$.Keyword}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.downloadtimes"}}</a> -->
</div> </div>
</div> </div>
@@ -184,9 +184,15 @@
</div> </div>
<div class="extra content" style="border-top: none !important;"> <div class="extra content" style="border-top: none !important;">
<div style="display: flex;align-items: center;"> <div style="display: flex;align-items: center;">
{{if eq .UserID 0}}
<a href="{{AppSubUrl}}/{{.Repo.OwnerName}}" title="{{.Repo.OwnerName}}"> <a href="{{AppSubUrl}}/{{.Repo.OwnerName}}" title="{{.Repo.OwnerName}}">
<img class="ui avatar image" style="width: 22px;height:22px;" src="/user/avatar/{{.Repo.OwnerName}}/-1"> <img class="ui avatar image" style="width: 22px;height:22px;" src="/user/avatar/{{.Repo.OwnerName}}/-1">
</a> </a>
{{else}}
<a href="{{AppSubUrl}}/{{.User.Name}}" title="{{.User.Name}}">
<img class="ui avatar image" style="width: 22px;height:22px;" src="/user/avatar/{{.User.Name}}/-1">
</a>
{{end}}
<span style="color: #999999;font-size: 14px;;">创建于:{{TimeSinceUnix1 .CreatedUnix}}</span> <span style="color: #999999;font-size: 14px;;">创建于:{{TimeSinceUnix1 .CreatedUnix}}</span>
</div> </div>
</div> </div>
@@ -215,4 +221,4 @@
</div> </div>
</div> </div>
</div> </div>
{{template "base/footer" .}}
{{template "base/footer" .}}

+ 237
- 54
templates/explore/organizations.tmpl View File

@@ -1,68 +1,251 @@

<link rel="stylesheet" href="/swiper/swiper-bundle.min.css">
<link rel="stylesheet" href="/css/git.openi.css">
<script src="/swiper/swiper-bundle.min.js"></script>
<script src="/self/js/jquery.min.js" type="text/javascript"></script>

{{template "base/head" .}} {{template "base/head" .}}
<div class="explore users"> <div class="explore users">
{{template "explore/search" .}}

<div class="ui container">
<div class="ui grid">
{{template "explore/navbar" .}}
<div class="sixteen wide mobile ten wide tablet ten wide computer column">
<h2 class="ui left floated medium header">
{{.i18n.Tr "explore.organizations"}}
</h2>
<div class="ui right floated secondary filter menu">
<!-- Sort -->
<div class="ui right dropdown type jump item">
<span class="text">
{{.i18n.Tr "repo.issues.filter_sort"}}
<i class="dropdown icon"></i>
</span>
<div class="menu">
<a class="{{if eq .SortType "newest"}}active{{end}} item" href="{{$.Link}}?sort=newest&q={{$.Keyword}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.latest"}}</a>
<a class="{{if eq .SortType "oldest"}}active{{end}} item" href="{{$.Link}}?sort=oldest&q={{$.Keyword}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.oldest"}}</a>
<a class="{{if eq .SortType "alphabetically"}}active{{end}} item" href="{{$.Link}}?sort=alphabetically&q={{$.Keyword}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.label.filter_sort.alphabetically"}}</a>
<a class="{{if eq .SortType "reversealphabetically"}}active{{end}} item" href="{{$.Link}}?sort=reversealphabetically&q={{$.Keyword}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.label.filter_sort.reverse_alphabetically"}}</a>
<a class="{{if eq .SortType "recentupdate"}}active{{end}} item" href="{{$.Link}}?sort=recentupdate&q={{$.Keyword}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.recentupdate"}}</a>
<a class="{{if eq .SortType "leastupdate"}}active{{end}} item" href="{{$.Link}}?sort=leastupdate&q={{$.Keyword}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.leastupdate"}}</a>
</div>
<!-- {{template "explore/search" .}} -->
<div class="repos--seach">
<div class="ui container">
<div class="ui two column centered grid">
<div class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" >
<div class="ui fluid action input" id="search_all">
<input id = 'value_s' name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search"}}..." onkeydown="if(event.keyCode==13){all_search();}" autofocus>
<input type="hidden" name="tab" value="{{$.TabName}}">
<button class="ui green button" onclick="all_search()">{{.i18n.Tr "explore.search"}}</button>
</div> </div>
</div> </div>
</div>
</div>
</div>


<div class="ui clearing divider"></div>

<div class="ui user list">
{{range .Users}}
<div class="item">
<img class="ui avatar image" src="{{.RelAvatarLink}}">
<div class="content">
<span class="header">
<a href="{{.HomeLink}}">{{.Name}}</a> {{.FullName}}
{{if .Visibility.IsPrivate}}
<span class="text gold">{{svg "octicon-lock" 16}}</span>
{{end}}
</span>
<div class="description">
{{if .Location}}
{{svg "octicon-location" 16}} {{.Location}}
{{end}}
{{if and .Website}}
{{svg "octicon-link" 16}}
<a href="{{.Website}}" rel="nofollow">{{.Website}}</a>
{{end}}
{{svg "octicon-clock" 16}} {{$.i18n.Tr "user.join_on"}} {{.CreatedUnix.FormatShort}}
</div>
</div>
<div class="ui container homeorg">
<div class="ui center aligned header">
<h1 class="title_re">
{{$.i18n.Tr "home.page_recommend_org"}}
</h1>
<p class="re_con"> {{$.i18n.Tr "home.page_recommend_org_desc"}}<a href="{{.RecommendURL}}"> {{$.i18n.Tr "home.page_recommend_org_commit"}}</a></p>
</div>

<div class="sixteen wide tablet sixteen wide computer column">
<div class="homeorg-list" >
<div class="swiper-wrapper" id="recommendorg" style="height:auto">
{{range .RecommendOrgs}}
<div class="swiper-slide">
<a href="{{.HomeLink}}" class= "ui fluid card">
<div class="content">
<div class= "ui small header">
<img class="ui image" src="{{.Avatar}}" >
<div class="content nowrap">
<span class="ui blue"> {{.Name}} </span> {{.FullName}}
<div class="sub header">
<span>
{{.NumRepos}}
{{if le .NumRepos 1}}
{{$.i18n.Tr "org.org_repository"}}
{{else}}
{{$.i18n.Tr "org.org_repositories"}}
{{end}}
</span>
. <span>
{{.NumMembers}}
{{if le .NumRepos 1}}
{{$.i18n.Tr "org.org_member"}}
{{else}}
{{$.i18n.Tr "org.org_members"}}
{{end}}
</span>
.<span>
{{.NumTeams}}
{{if le .NumRepos 1}}
{{$.i18n.Tr "org.org_team"}}
{{else}}
{{$.i18n.Tr "org.org_teams"}}
{{end}}
</span>
</div>
</div>
</div>
</div>
</a>
</div> </div>
{{else}}
<div>{{$.i18n.Tr "explore.org_no_results"}}</div>
{{end}} {{end}}
</div> </div>

{{template "base/paginate" .}}
<div class="swiper-pagination"></div>
</div> </div>
<div class="sixteen wide mobile six wide tablet three wide computer column">
{{template "explore/repo_right" .}}
</div>
</div>
<div class="ui container homeorg">
<div class="content_top10">
<div class="ui three doubling cards">
<div class="card_list" >
<div class="list_title star_title">
<p class="p_text"> <i class="ri-star-line"> </i>{{$.i18n.Tr "org.star"}}</p>
</div>
<li style="list-style:none">
{{ range $i,$user :=.StarOrgs}}
<ul class="orgs" style="display: flex;">
{{if eq $i 0}}
<div class="org_icon">
<svg width="1em" height="1em" viewBox="0 0 32 32" class="contribution-item-img__2-fih"><defs><path id="rank1_svg__a" d="M13.69 20V9.616h-1.598l-3.139 2.61 1.027 1.218 1.95-1.804V20z"></path></defs><g fill="none" fill-rule="evenodd"><path d="M0 0h32v32H0z"></path><g transform="translate(4 2.667)"><path fill="#D16C11" d="M0 0h6.976l5.49 7.642L17.063 0H24L12 16z"></path><circle fill="#F7C049" cx="12" cy="14.667" r="12"></circle><circle fill="#FEE6AD" cx="12" cy="14.667" r="9.333"></circle><g fill-rule="nonzero"><use fill="#FFF" xlink:href="#rank1_svg__a"></use><use fill="#D74D03" xlink:href="#rank1_svg__a"></use></g></g></g></svg>
</div>
{{else if eq $i 1}}
<div class="org_icon">
<svg width="1em" height="1em" viewBox="0 0 32 32" class="contribution-item-img__2-fih"><g transform="translate(4 2.667)" fill="none" fill-rule="evenodd"><path fill="#305269" d="M0 0h6.976l5.49 7.642L17.063 0H24L12 16z"></path><circle fill="#BDD8F0" cx="12" cy="14.667" r="12"></circle><circle fill="#E1E9FC" cx="12" cy="14.667" r="9.333"></circle><path d="M15.817 20v-1.584h-4.81l3.212-2.977c.469-.43.853-.883 1.151-1.357.298-.474.447-1.039.447-1.694 0-.499-.088-.934-.264-1.305a2.525 2.525 0 00-.718-.917 3.169 3.169 0 00-1.064-.543 4.531 4.531 0 00-1.312-.183c-.47 0-.905.064-1.306.19-.4.128-.753.314-1.056.558-.303.244-.55.55-.74.917-.191.366-.306.79-.345 1.268l1.848.147c.059-.43.23-.772.513-1.027.284-.254.646-.381 1.086-.381.205 0 .398.032.579.095.18.064.34.154.477.272a1.262 1.262 0 01.455.997c0 .176-.035.345-.103.506a2.52 2.52 0 01-.257.462 3.476 3.476 0 01-.345.418c-.127.132-.249.257-.366.374l-4.034 3.901V20h6.952z" fill="#305269" fill-rule="nonzero"></path></g></svg>
</div>
{{else if eq $i 2}}
<div class="org_icon">
<svg width="1em" height="1em" viewBox="0 0 32 32" class="contribution-item-img__2-fih"><g transform="translate(4 2.667)" fill="none" fill-rule="evenodd"><path fill="#865B45" d="M0 0h6.976l5.49 7.642L17.063 0H24L12 16z"></path><circle fill="#E7C5AC" cx="12" cy="14.667" r="12"></circle><circle fill="#FEDDC7" cx="12" cy="14.667" r="9.333"></circle><path d="M12.239 20.176c.46 0 .902-.066 1.327-.198.425-.132.8-.328 1.122-.587.323-.259.58-.579.77-.96.19-.382.286-.822.286-1.32 0-.646-.171-1.203-.513-1.672-.343-.47-.846-.753-1.511-.851v-.03c.557-.136.992-.422 1.305-.857.313-.435.47-.932.47-1.489 0-.46-.09-.863-.272-1.21a2.547 2.547 0 00-.726-.865 3.232 3.232 0 00-1.056-.521 4.521 4.521 0 00-1.276-.176 4.52 4.52 0 00-1.1.132 3.404 3.404 0 00-.968.403 2.79 2.79 0 00-.762.697 3.181 3.181 0 00-.499.997l1.863.499c.127-.362.33-.643.608-.843.279-.2.594-.301.946-.301.44 0 .797.127 1.071.381.274.255.41.582.41.983 0 .313-.058.562-.175.748a1.17 1.17 0 01-.462.425 1.903 1.903 0 01-.646.191 6.09 6.09 0 01-.74.044h-.455v1.584h.425c.264 0 .533.02.807.059.274.039.52.115.74.227.22.112.402.274.543.484.142.21.213.482.213.814a1.533 1.533 0 01-.52 1.18 1.772 1.772 0 01-.558.33 1.88 1.88 0 01-.667.118c-.47 0-.841-.117-1.115-.352s-.464-.567-.572-.997l-1.877.498c.117.43.288.8.513 1.108.225.308.491.56.8.755.307.196.652.34 1.033.433a5.13 5.13 0 001.218.139z" fill="#865B45" fill-rule="nonzero"></path></g></svg>
</div>
{{else }}
<div class="org_icon org_icon_num" >
{{Add $i 1}}
</div>
{{end}}
<li class="li_avatar">
<img class="ui avatar image" src="{{$user.RelAvatarLink}}" >
</li>
<li class="li_name">
<p class="org_line_hight">{{$user.Name}}</p>
</li>
<ul>
<li class="li_score" >
<i class="ri-star-line org_line_hight org_icon_color"></i> &nbsp;<p class="p_score">{{$user.Score}}</p>
</li>
</ul>

</ul>
{{end}}
</li>
</div>
<div class="card_list" >
<div class="list_title star_title">
<p class="p_text"> <i class="ri-user-2-line"> </i>{{$.i18n.Tr "org.member"}}</p>
</div>
<li style="list-style:none">
{{ range $i,$user :=.StarOrgs}}
<ul class="orgs" style="display: flex;">
{{if eq $i 0}}
<div class="org_icon">
<svg width="1em" height="1em" viewBox="0 0 32 32" class="contribution-item-img__2-fih"><defs><path id="rank1_svg__a" d="M13.69 20V9.616h-1.598l-3.139 2.61 1.027 1.218 1.95-1.804V20z"></path></defs><g fill="none" fill-rule="evenodd"><path d="M0 0h32v32H0z"></path><g transform="translate(4 2.667)"><path fill="#D16C11" d="M0 0h6.976l5.49 7.642L17.063 0H24L12 16z"></path><circle fill="#F7C049" cx="12" cy="14.667" r="12"></circle><circle fill="#FEE6AD" cx="12" cy="14.667" r="9.333"></circle><g fill-rule="nonzero"><use fill="#FFF" xlink:href="#rank1_svg__a"></use><use fill="#D74D03" xlink:href="#rank1_svg__a"></use></g></g></g></svg>
</div>
{{else if eq $i 1}}
<div class="org_icon">
<svg width="1em" height="1em" viewBox="0 0 32 32" class="contribution-item-img__2-fih"><g transform="translate(4 2.667)" fill="none" fill-rule="evenodd"><path fill="#305269" d="M0 0h6.976l5.49 7.642L17.063 0H24L12 16z"></path><circle fill="#BDD8F0" cx="12" cy="14.667" r="12"></circle><circle fill="#E1E9FC" cx="12" cy="14.667" r="9.333"></circle><path d="M15.817 20v-1.584h-4.81l3.212-2.977c.469-.43.853-.883 1.151-1.357.298-.474.447-1.039.447-1.694 0-.499-.088-.934-.264-1.305a2.525 2.525 0 00-.718-.917 3.169 3.169 0 00-1.064-.543 4.531 4.531 0 00-1.312-.183c-.47 0-.905.064-1.306.19-.4.128-.753.314-1.056.558-.303.244-.55.55-.74.917-.191.366-.306.79-.345 1.268l1.848.147c.059-.43.23-.772.513-1.027.284-.254.646-.381 1.086-.381.205 0 .398.032.579.095.18.064.34.154.477.272a1.262 1.262 0 01.455.997c0 .176-.035.345-.103.506a2.52 2.52 0 01-.257.462 3.476 3.476 0 01-.345.418c-.127.132-.249.257-.366.374l-4.034 3.901V20h6.952z" fill="#305269" fill-rule="nonzero"></path></g></svg>
</div>
{{else if eq $i 2}}
<div class="org_icon">
<svg width="1em" height="1em" viewBox="0 0 32 32" class="contribution-item-img__2-fih"><g transform="translate(4 2.667)" fill="none" fill-rule="evenodd"><path fill="#865B45" d="M0 0h6.976l5.49 7.642L17.063 0H24L12 16z"></path><circle fill="#E7C5AC" cx="12" cy="14.667" r="12"></circle><circle fill="#FEDDC7" cx="12" cy="14.667" r="9.333"></circle><path d="M12.239 20.176c.46 0 .902-.066 1.327-.198.425-.132.8-.328 1.122-.587.323-.259.58-.579.77-.96.19-.382.286-.822.286-1.32 0-.646-.171-1.203-.513-1.672-.343-.47-.846-.753-1.511-.851v-.03c.557-.136.992-.422 1.305-.857.313-.435.47-.932.47-1.489 0-.46-.09-.863-.272-1.21a2.547 2.547 0 00-.726-.865 3.232 3.232 0 00-1.056-.521 4.521 4.521 0 00-1.276-.176 4.52 4.52 0 00-1.1.132 3.404 3.404 0 00-.968.403 2.79 2.79 0 00-.762.697 3.181 3.181 0 00-.499.997l1.863.499c.127-.362.33-.643.608-.843.279-.2.594-.301.946-.301.44 0 .797.127 1.071.381.274.255.41.582.41.983 0 .313-.058.562-.175.748a1.17 1.17 0 01-.462.425 1.903 1.903 0 01-.646.191 6.09 6.09 0 01-.74.044h-.455v1.584h.425c.264 0 .533.02.807.059.274.039.52.115.74.227.22.112.402.274.543.484.142.21.213.482.213.814a1.533 1.533 0 01-.52 1.18 1.772 1.772 0 01-.558.33 1.88 1.88 0 01-.667.118c-.47 0-.841-.117-1.115-.352s-.464-.567-.572-.997l-1.877.498c.117.43.288.8.513 1.108.225.308.491.56.8.755.307.196.652.34 1.033.433a5.13 5.13 0 001.218.139z" fill="#865B45" fill-rule="nonzero"></path></g></svg>
</div>
{{else }}
<div class="org_icon org_icon_num" >
{{Add $i 1}}
</div>
{{end}}
<li class="li_avatar">
<img class="ui avatar image" src="{{$user.RelAvatarLink}}" >
</li>
<li class="li_name">
<p class="org_line_hight">{{$user.Name}}</p>
</li>
<ul>
<li class="li_score">
<i class="ri-user-2-line org_line_hight org_icon_color"></i> &nbsp;<p class="p_score">{{$user.Score}}</p>
</li>
</ul>

</ul>
{{end}}
</li>
</div>
<div class="card_list" >
<div class="list_title star_title">
<p class="p_text"> <i class="ri-blaze-fill"> </i>{{$.i18n.Tr "org.active"}}</p>
</div>
<li style="list-style:none">
{{ range $i,$user :=.StarOrgs}}
<ul class="orgs" style="display: flex;">
{{if eq $i 0}}
<div class="org_icon">
<svg width="1em" height="1em" viewBox="0 0 32 32" class="contribution-item-img__2-fih"><defs><path id="rank1_svg__a" d="M13.69 20V9.616h-1.598l-3.139 2.61 1.027 1.218 1.95-1.804V20z"></path></defs><g fill="none" fill-rule="evenodd"><path d="M0 0h32v32H0z"></path><g transform="translate(4 2.667)"><path fill="#D16C11" d="M0 0h6.976l5.49 7.642L17.063 0H24L12 16z"></path><circle fill="#F7C049" cx="12" cy="14.667" r="12"></circle><circle fill="#FEE6AD" cx="12" cy="14.667" r="9.333"></circle><g fill-rule="nonzero"><use fill="#FFF" xlink:href="#rank1_svg__a"></use><use fill="#D74D03" xlink:href="#rank1_svg__a"></use></g></g></g></svg>
</div>
{{else if eq $i 1}}
<div class="org_icon">
<svg width="1em" height="1em" viewBox="0 0 32 32" class="contribution-item-img__2-fih"><g transform="translate(4 2.667)" fill="none" fill-rule="evenodd"><path fill="#305269" d="M0 0h6.976l5.49 7.642L17.063 0H24L12 16z"></path><circle fill="#BDD8F0" cx="12" cy="14.667" r="12"></circle><circle fill="#E1E9FC" cx="12" cy="14.667" r="9.333"></circle><path d="M15.817 20v-1.584h-4.81l3.212-2.977c.469-.43.853-.883 1.151-1.357.298-.474.447-1.039.447-1.694 0-.499-.088-.934-.264-1.305a2.525 2.525 0 00-.718-.917 3.169 3.169 0 00-1.064-.543 4.531 4.531 0 00-1.312-.183c-.47 0-.905.064-1.306.19-.4.128-.753.314-1.056.558-.303.244-.55.55-.74.917-.191.366-.306.79-.345 1.268l1.848.147c.059-.43.23-.772.513-1.027.284-.254.646-.381 1.086-.381.205 0 .398.032.579.095.18.064.34.154.477.272a1.262 1.262 0 01.455.997c0 .176-.035.345-.103.506a2.52 2.52 0 01-.257.462 3.476 3.476 0 01-.345.418c-.127.132-.249.257-.366.374l-4.034 3.901V20h6.952z" fill="#305269" fill-rule="nonzero"></path></g></svg>
</div>
{{else if eq $i 2}}
<div class="org_icon">
<svg width="1em" height="1em" viewBox="0 0 32 32" class="contribution-item-img__2-fih"><g transform="translate(4 2.667)" fill="none" fill-rule="evenodd"><path fill="#865B45" d="M0 0h6.976l5.49 7.642L17.063 0H24L12 16z"></path><circle fill="#E7C5AC" cx="12" cy="14.667" r="12"></circle><circle fill="#FEDDC7" cx="12" cy="14.667" r="9.333"></circle><path d="M12.239 20.176c.46 0 .902-.066 1.327-.198.425-.132.8-.328 1.122-.587.323-.259.58-.579.77-.96.19-.382.286-.822.286-1.32 0-.646-.171-1.203-.513-1.672-.343-.47-.846-.753-1.511-.851v-.03c.557-.136.992-.422 1.305-.857.313-.435.47-.932.47-1.489 0-.46-.09-.863-.272-1.21a2.547 2.547 0 00-.726-.865 3.232 3.232 0 00-1.056-.521 4.521 4.521 0 00-1.276-.176 4.52 4.52 0 00-1.1.132 3.404 3.404 0 00-.968.403 2.79 2.79 0 00-.762.697 3.181 3.181 0 00-.499.997l1.863.499c.127-.362.33-.643.608-.843.279-.2.594-.301.946-.301.44 0 .797.127 1.071.381.274.255.41.582.41.983 0 .313-.058.562-.175.748a1.17 1.17 0 01-.462.425 1.903 1.903 0 01-.646.191 6.09 6.09 0 01-.74.044h-.455v1.584h.425c.264 0 .533.02.807.059.274.039.52.115.74.227.22.112.402.274.543.484.142.21.213.482.213.814a1.533 1.533 0 01-.52 1.18 1.772 1.772 0 01-.558.33 1.88 1.88 0 01-.667.118c-.47 0-.841-.117-1.115-.352s-.464-.567-.572-.997l-1.877.498c.117.43.288.8.513 1.108.225.308.491.56.8.755.307.196.652.34 1.033.433a5.13 5.13 0 001.218.139z" fill="#865B45" fill-rule="nonzero"></path></g></svg>
</div>
{{else }}
<div class="org_icon org_icon_num" >
{{Add $i 1}}
</div>
{{end}}
<li class="li_avatar">
<img class="ui avatar image" src="{{$user.RelAvatarLink}}" >
</li>
<li class="li_name">
<p class="org_line_hight">{{$user.Name}}</p>
</li>

</ul>
{{end}}
</li>
</div>
</div> </div>
</div> </div>
</div> </div>



</div> </div>

{{template "base/footer" .}} {{template "base/footer" .}}

<script>


function all_search(){
var inputValue = document.getElementById("value_s").value;
console.log("Keyword",inputValue)
sessionStorage.setItem("keyword",inputValue);
sessionStorage.setItem("tableName","org");
sessionStorage.setItem("specifySearch",true);
sessionStorage.setItem("sortBy","default");
sessionStorage.setItem("ascending","false");
window.open("/all/search/");

}

window.onload = function() {
var swiperOrg = new Swiper(".homeorg-list", {
slidesPerView: 1,
slidesPerColumn: 3,
slidesPerColumnFill:'row',
spaceBetween: 15,
pagination: {
el: ".swiper-pagination",
clickable: true,
},
autoplay: {
delay: 4500,
disableOnInteraction: false,
},
breakpoints: {
768: {
slidesPerView: 3,
},
1024: {
slidesPerView: 4,
},
},

});

}

</script>

+ 13
- 1
templates/explore/repos.tmpl View File

@@ -10,7 +10,19 @@


<div class="ui sixteen wide mobile twelve wide tablet ten wide computer column"> <div class="ui sixteen wide mobile twelve wide tablet ten wide computer column">
{{template "explore/repo_list" .}} {{template "explore/repo_list" .}}
{{template "base/paginate" .}}
<div id="app" style="margin-top: 2rem;">
<div class="center">
<el-pagination
background
@current-change="handleCurrentChange"
:current-page="page"
:page-sizes="[20]"
:page-size="20"
layout="total, sizes, prev, pager, next, jumper"
:total="{{.Page.Paginater.Total}}">
</el-pagination>
</div>
</div>
</div> </div>
<div class="computer only ui three wide computer column"> <div class="computer only ui three wide computer column">
{{template "explore/repo_right" .}} {{template "explore/repo_right" .}}


+ 95
- 0
templates/explore/search_new.tmpl View File

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

<div class="explore seach">
<div class="repos--seach">
<div class="ui container">
<div id="search_div" class="ui two column centered grid">
<div class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin-top:1.2rem;margin-bottom: 1.2rem;">
<div class="ui fluid action input">
<input name="q" id="keyword_input" value="{{.Keyword}}" placeholder="{{.i18n.Tr "home.search"}}..." autofocus="">
<input type="hidden" name="topic" value="">
<input type="hidden" name="tab" value="">
<input type="hidden" name="sort" value="hot">
<button class="ui green button" onclick="search()">{{.i18n.Tr "home.search"}}</button>
</div>
</div>
</div>
<div id="search_label_div" style="display:none">
</div>
</div>

<div class="ui container seachnav">
<div class="ui secondary pointing menu">
<a id="repo_item" class="item" href="javascript:searchItem(1,10);">
{{.i18n.Tr "home.search_repo"}}
<span class="ui circular mini label" id="repo_total"></span>
</a>
<a id="dataset_item" class="item" href="javascript:searchItem(5,50);">
{{.i18n.Tr "home.search_dataset"}}
<span class="ui circular mini label" id="dataset_total"></span>
</a>
<a id="issue_item" class="item" href="javascript:searchItem(2,20);">
{{.i18n.Tr "home.search_issue"}}
<span class="ui circular mini label" id="issue_total"></span>
</a>
<a id="pr_item" class="item" href="javascript:searchItem(6,60);">
{{.i18n.Tr "home.search_pr"}}
<span class="ui circular mini label" id="pr_total"></span>
</a>
<a id="user_item" class="item" href="javascript:searchItem(3,30);">
{{.i18n.Tr "home.search_user"}}
<span class="ui circular mini label" id="user_total"></span>
</a>
<a id="org_item" class="item" href="javascript:searchItem(4,40);">
{{.i18n.Tr "home.search_org"}} <span class="ui circular mini label" id="org_total"></span>
</a>
</div>
</div>
</div>

<div class="ui container">
<span id="find_id">{{.i18n.Tr "home.search_finded"}}</span><span id="find_title"></span>
<div class="ui right floated secondary filter menu">
<!-- Sort -->
<div class="ui right dropdown type jump item">
<span class="text">
{{.i18n.Tr "repo.issues.filter_sort"}}
<i class="dropdown icon"></i>
</span>
<div class="menu" id="sort_type">
</div>
</div>

</div>
<div class="ui divider" style="margin-top: 1.25rem;"></div>

<div class="ui very relaxed divided list" id="child_search_item">

</div><!--seach list end-->
<div class="center page buttons" style="margin: 0px auto 15px">
<div class="ui borderless mini pagination menu" id="page_menu">
</div>
</div>
<div id="tipmsg"></div>
</div>

</div>
<script src="/self/js/jquery.min.js" type="text/javascript"></script>
<script src="/home/search.js?v={{MD5 AppVer}}" type="text/javascript"></script>
<div class="am-mt-30"></div>


{{template "base/footer" .}}

+ 13
- 1
templates/repo/cloudbrain/benchmark/index.tmpl View File

@@ -185,7 +185,19 @@
</div> </div>
--> -->


{{template "base/paginate" .}}
<div id="app" style="margin-top: 2rem;">
<div class="center">
<el-pagination
background
@current-change="handleCurrentChange"
:current-page="page"
:page-sizes="[10]"
:page-size="10"
layout="total, sizes, prev, pager, next, jumper"
:total="{{.Page.Paginater.Total}}">
</el-pagination>
</div>
</div>
</div> </div>


</div> </div>


+ 21
- 8
templates/repo/cloudbrain/benchmark/show.tmpl View File

@@ -196,7 +196,13 @@ td, th {
<span class="accordion-panel-title-content"> <span class="accordion-panel-title-content">
<span> <span>
<div class="ac-display-inblock title_text acc-margin-bottom"> <div class="ac-display-inblock title_text acc-margin-bottom">
<span class="cti-mgRight-sm">{{TimeSinceUnix1 .CreatedUnix}}</span>
<span class="cti-mgRight-sm">
{{if not (eq .StartTime 0)}}
<td>{{TimeSinceUnix1 .StartTime}}</td>
{{else}}
<td>{{TimeSinceUnix1 .CreatedUnix}}<td>
{{end}}
</span>


<span class="cti-mgRight-sm">{{$.i18n.Tr "repo.modelarts.status"}}: <span class="cti-mgRight-sm">{{$.i18n.Tr "repo.modelarts.status"}}:
<span id="{{.VersionName}}-status-span"><i id="icon" style="vertical-align: middle;" class="{{.Status}}"></i><span id="text" style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span> <span id="{{.VersionName}}-status-span"><i id="icon" style="vertical-align: middle;" class="{{.Status}}"></i><span id="text" style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span>
@@ -252,7 +258,13 @@ td, th {


<td class="ti-text-form-content"> <td class="ti-text-form-content">
<div class="text-span text-span-w"> <div class="text-span text-span-w">
<span style="font-size: 12px;" class="">{{TimeSinceUnix1 .CreatedUnix}}</span>
<span style="font-size: 12px;" class="">
{{if not (eq .StartTime 0)}}
{{TimeSinceUnix1 .StartTime}}
{{else}}
{{TimeSinceUnix1 .CreatedUnix}}
{{end}}
</span>
</div> </div>
</td> </td>
</tr> </tr>
@@ -269,7 +281,7 @@ td, th {
</tr> </tr>
<tr class="ti-no-ng-animate"> <tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80"> <td class="ti-no-ng-animate ti-text-form-label text-width80">
镜像
{{.i18n.Tr "cloudbrain.mirror"}}
</td> </td>


<td class="ti-text-form-content"> <td class="ti-text-form-content">
@@ -280,7 +292,8 @@ td, th {
</tr> </tr>
<tr class="ti-no-ng-animate"> <tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80"> <td class="ti-no-ng-animate ti-text-form-label text-width80">
类型
{{.i18n.Tr "repo.cloudbrain.benchmark.evaluate_type"}}
</td> </td>


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


<tr class="ti-no-ng-animate"> <tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80"> <td class="ti-no-ng-animate ti-text-form-label text-width80">
训练程序
{{.i18n.Tr "repo.cloudbrain.benchmark.evaluate_train"}}
</td> </td>


<td class="ti-text-form-content"> <td class="ti-text-form-content">
@@ -312,7 +325,7 @@ td, th {
</tr> </tr>
<tr class="ti-no-ng-animate"> <tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80"> <td class="ti-no-ng-animate ti-text-form-label text-width80">
测试程序
{{.i18n.Tr "repo.cloudbrain.benchmark.evaluate_test"}}
</td> </td>


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


<tr class="ti-no-ng-animate"> <tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80"> <td class="ti-no-ng-animate ti-text-form-label text-width80">
创建者
{{$.i18n.Tr "repo.cloudbrain_creator"}}
</td> </td>


<td class="ti-text-form-content"> <td class="ti-text-form-content">
@@ -359,7 +372,7 @@ td, th {
</tr> </tr>
<tr class="ti-no-ng-animate"> <tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80"> <td class="ti-no-ng-animate ti-text-form-label text-width80">
子类型
{{$.i18n.Tr "repo.cloudbrain.benchmark.evaluate_child_type"}}
</td> </td>


<td class="ti-text-form-content"> <td class="ti-text-form-content">


+ 491
- 90
templates/repo/cloudbrain/show.tmpl View File

@@ -1,100 +1,501 @@
{{template "base/head" .}} {{template "base/head" .}}
<style>
.according-panel-heading{
box-sizing: border-box;
padding: 8px 16px;
color: #252b3a;
background-color: #f2f5fc;
line-height: 1.5;
cursor: pointer;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
-khtml-user-select: none;
user-select: none;
}
.accordion-panel-title {
margin-top: 0;
margin-bottom: 0;
color: #252b3a;
}
.accordion-panel-title-content{
vertical-align: middle;
display: inline-block;
width: calc(100% - 32px);
cursor: default;
}
.acc-margin-bottom {
margin-bottom: 5px;
}
.title_text {
font-size: 12px;
}
.ac-display-inblock {
display: inline-block;
}
.cti-mgRight-sm {
margin-right: 8px;
}
.ac-text-normal {
font-size: 14px;
color: #575d6c;
}
.uc-accordionTitle-black {
color: #333;
}
.accordion-border{
border:1px solid #cce2ff;
}
.padding0{
padding: 0 !important;
}
.content-pad{
padding: 15px 35px;
}
.content-margin{
margin:10px 5px ;
}
.tab_2_content {
min-height: 560px;
margin-left: 10px;
}
.ac-grid {
display: block;
*zoom: 1;
}
.ac-grid-col {
float: left;
width: 100%;
}
.ac-grid-col2 .ac-grid-col {
width: 50%;
}
.ti-form {
text-align: left;
max-width: 100%;
vertical-align: middle;
}
.ti-form>tbody {
font-size: 12px;
}
.ti-form>tbody, .ti-form>tbody>tr {
vertical-align: inherit;
}
.info_text {
padding-bottom: 20px;
padding-right: 20px;
font-size: 12px;
}

.ti-text-form-label {

padding-bottom: 20px;
padding-right: 20px;
color: #8a8e99;
font-size: 12px;
white-space: nowrap !important;
width: 80px;
line-height: 30px;
}
.ti-text-form-content{
line-height: 30px;
padding-bottom: 20px;
}
.ti-form>tbody>tr>td {
vertical-align: top;
white-space: normal;
}
td, th {
padding: 0;
}
.ac-grid-col .text-span {
width: 450px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.redo-color{
color: #3291F8;
}
.ti-action-menu-item:not(:last-child){
margin-right: 10px;
padding-right: 11px;
text-decoration: none!important;
color: #526ecc;
cursor: pointer;
display: inline-block;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
-khtml-user-select: none;
user-select: none;
position: relative;
}
.ti-action-menu-item:not(:last-child):after {
content: "";
display: inline-block;
position: absolute;
height: 12px;
right: 0;
top: 50%;
-webkit-transform: translateY(-6px);
-ms-transform: translateY(-6px);
-o-transform: translateY(-6px);
transform: translateY(-6px);
border-right: 1px solid #dfe1e6;
}
.text-width80{
width: 100px;
line-height: 30px;
}
.border-according{
border: 1px solid #dfe1e6;
}
.disabled {
cursor: default;
pointer-events: none;
color: rgba(0,0,0,.6) !important;
opacity: .45 !important;
}
.pad20{

border:0px !important;
}
.model_file_bread{
margin-bottom: -0.5rem !important;
padding-left: 1rem;
padding-top: 0.5rem ;
}
</style>
<div id="mask">
<div id="loadingPage">
<div class="rect1"></div>
<div class="rect2"></div>
<div class="rect3"></div>
<div class="rect4"></div>
<div class="rect5"></div>
</div>
</div>
<div class="repository"> <div class="repository">
{{template "repo/header" .}} {{template "repo/header" .}}
<div class="repository new repo ui middle very relaxed page grid">
<div class="column">
{{template "base/alert" .}}

<div class="ui container">
<h4 class="ui header" id="vertical-segment"> <h4 class="ui header" id="vertical-segment">
<div class="ui breadcrumb">
<a class="section" href="{{.RepoLink}}/debugjob?debugListType=all">
{{.i18n.Tr "repo.cloudbrain"}}
</a>
<div class="divider"> / </div>
<a class="section backTodeBug" href="{{.RepoLink}}/debugjob?debugListType={{if eq $.debugListType "NPU"}}NPU{{else if eq $.debugListType "CPU/GPU"}}CPU/GPU{{else}}all{{end}}">
{{$.i18n.Tr "repo.modelarts.notebook"}}
</a>
<div class="divider"> / </div>
{{with .task}}
<div class="active section">{{.DisplayJobName}}</div>
{{end}}
</div>
<div class="ui breadcrumb">
<a class="section" href="{{.RepoLink}}/debugjob?debugListType=all">
{{.i18n.Tr "repo.cloudbrain"}}
</a>
<div class="divider"> / </div>
<a class="section backTodeBug" href="{{.RepoLink}}/debugjob?debugListType={{if eq $.debugListType "NPU"}}NPU{{else if eq $.debugListType "CPU/GPU"}}CPU/GPU{{else}}all{{end}}">
{{$.i18n.Tr "repo.modelarts.notebook"}}
</a>
<div class="divider"> / </div>
<div class="active section">{{.displayJobName}}</div>
</div>
</h4> </h4>
<div>
<div class="ui yellow segment">
{{with .task}}
<p>任务名称: {{.DisplayJobName}}</p>
{{end}}
</div>
<div class="ui green segment">
<p>任务结果:</p>
{{with .taskRes}}
{{range .TaskStatuses}}
<table class="ui celled striped table">
<tbody>
<tr>
<td class="four wide"> 状态 </td>
<td> {{.State}} </td>
</tr>
</tbody>
</table>
{{end}}
{{end}}
</div>
<div class="ui blue segment">
{{with .result}}
<table class="ui celled striped table">
<thead>
<tr> <th colspan="2"> 硬件信息 </th> </tr>
</thead>
<tbody>
<tr>
<td class="four wide"> CPU </td>
<td>{{.Resource.CPU}}</td>
</tr>
<tr>
<td> Memory </td>
<td>{{.Resource.Memory}}</td>
</tr>
<tr>
<td> NvidiaComGpu </td>
<td>{{.Resource.NvidiaComGpu}}</td>
</tr>
</tbody>
</table>

<table class="ui celled striped table">
<thead>
<tr> <th colspan="2"> 调试信息 </th> </tr>
</thead>
<tbody>
<tr>
<td class="four wide"> 平台 </td>
<td> {{.Platform}} </td>
</tr>
<tr>
<td> 开始时间 </td>
<td>{{.JobStatus.StartTime}}</td>
</tr>
<tr>
<td> 结束时间 </td>
<td>{{.JobStatus.EndTime}}</td>
</tr>
<tr>
<td> ExitCode </td>
<td>{{.JobStatus.AppExitCode}}</td>
</tr>
<tr>
<td> 退出信息 </td>
<td>{{.JobStatus.AppExitDiagnostics | nl2br}}</td>
</tr>
</tbody>
</table>
{{end}}
</div>
{{range $k ,$v := .version_list_task}}
<div class="ui accordion border-according" id="accordion{{.VersionName}}" data-repopath="{{$.RepoRelPath}}" data-jobid="{{.JobID}}" data-version="{{.VersionName}}">
<input type="hidden" id="jobId_input" name="jobId_input" value="{{.JobID}}">
<div class="{{if eq $k 0}}active{{end}} title padding0">
<div class="according-panel-heading">
<div class="accordion-panel-title">
<i class="dropdown icon"></i>
<span class="accordion-panel-title-content">
<span>
<div class="ac-display-inblock title_text acc-margin-bottom">
<span class="cti-mgRight-sm">
{{if not (eq .StartTime 0)}}
<td>{{TimeSinceUnix1 .StartTime}}</td>
{{else}}
<td>{{TimeSinceUnix1 .CreatedUnix}}<td>
{{end}}
</span>

<span class="cti-mgRight-sm">{{$.i18n.Tr "repo.modelarts.status"}}:
<span id="{{.VersionName}}-status-span"><i id="icon" style="vertical-align: middle;" class="{{.Status}}"></i><span id="text" style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span>
</span>
<span class="cti-mgRight-sm">{{$.i18n.Tr "repo.modelarts.train_job.dura_time"}}:</span>
<span class="cti-mgRight-sm uc-accordionTitle-black" id="{{.VersionName}}-duration-span">{{$.duration}}</span>

</div>
</span>
</span>
</div>
</div>
</div>
<div class="{{if eq $k 0}}active{{end}} content">
<div class="content-pad">
<div class="ui pointing secondary menu" style="border-bottom: 1px solid rgba(34,36,38,.15);">
<a class="active item" data-tab="first{{$k}}">{{$.i18n.Tr "repo.modelarts.train_job.config"}}</a>
</div>
<div class="ui tab active" data-tab="first{{$k}}">
<div style="padding-top: 10px;">
<div class="tab_2_content">
<div class="ac-grid ac-grid-col2">
<div class="ac-grid-col">
<table class="ti-form">
<tbody class="ti-text-form">
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "repo.cloudbrain_task"}}
</td>
<td class="ti-text-form-content">
<div class="text-span text-span-w">
{{.DisplayJobName}}
</div>
</td>
</tr>
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "repo.modelarts.status"}}
</td>

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

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

<td class="ti-text-form-content">
<div class="text-span text-span-w">
<span style="font-size: 12px;" class="">
{{if not (eq .StartTime 0)}}
{{TimeSinceUnix1 .StartTime}}
{{else}}
{{TimeSinceUnix1 .CreatedUnix}}
{{end}}
</span>
</div>
</td>
</tr>
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "repo.modelarts.train_job.dura_time"}}
</td>

<td class="ti-text-form-content">
<div class="text-span text-span-w" id="{{.VersionName}}-duration">
{{$.duration}}
</div>
</td>
</tr>
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "cloudbrain.mirror"}}
</td>

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

<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "cloudbrain.dataset_storage_path"}}
</td>

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

<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "cloudbrain.code_storage_path"}}
</td>

<td class="ti-text-form-content">
<div class="text-span text-span-w" id="code_storage_path">
{{$.code_path}}
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div class="ac-grid-col">
<table class="ti-form">
<tbody class="ti-text-form">


<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "cloudbrain.gpu_type"}}
</td>

<td class="ti-text-form-content">
<div class="text-span text-span-w">
{{$.resource_type}}
</div>
</td>
</tr>
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
ExitCode
</td>

<td class="ti-text-form-content">
<div class="text-span text-span-w">
{{$.result.JobStatus.AppExitCode}}
</div>
</td>
</tr>
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "repo.cloudbrain.endtime"}}
</td>

<td class="ti-text-form-content">
<div class="text-span text-span-w" id="{{.VersionName}}-BenchmarkTypeName">
{{if not (eq .EndTime 0)}}
{{TimeSinceUnix1 .EndTime}}
{{else}}
--
{{end}}
</div>
</td>
</tr>
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "repo.modelarts.train_job.dataset"}}
</td>

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


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

<td class="ti-text-form-content">
<div class="text-span text-span-w">
{{$.i18n.Tr "cloudbrain.gpu_num"}}:{{$.GpuNum}},{{$.i18n.Tr "cloudbrain.cpu_num"}}:{{$.CpuNum}},{{$.i18n.Tr "cloudbrain.memory"}}(MB):{{$.MemMiB}},{{$.i18n.Tr "cloudbrain.shared_memory"}}(MB):{{$.ShareMemMiB}}
</div>
</td>
</tr>

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

<td class="ti-text-form-content">
<div class="text-span text-span-w" id="{{.VersionName}}-mirror">
{{.User.Name}}
</div>
</td>
</tr>
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "cloudbrain.model_storage_path"}}
</td>

<td class="ti-text-form-content">
<div class="text-span text-span-w" id="model_storage_path">
{{$.model_path}}
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="ac-grid ac-grid-col2">
<div class="ac-grid-col">
<span class="ti-text-form-label">{{$.i18n.Tr "repo.cloudbrain.exitinfo"}}</span>
</div>
</div>
<div class="ac-grid-col">
<span class="info_text">
{{$.result.JobStatus.AppExitDiagnostics}}
</span>
</div>
</div>

</div>
</div>

</div>
</div>
</div> </div>
{{end}} {{template "base/paginate" .}}
</div>
<!-- 确认模态框 -->
<div id="deletemodel">
<div class="ui basic modal">
<div class="ui icon header">
<i class="trash icon"></i> {{.i18n.Tr "cloudbrain.delete_task"}}
</div>


<div class="content">
<p>{{.i18n.Tr "cloudbrain.task_delete_confirm"}}</p>
</div>
<div class="actions">
<div class="ui red basic inverted cancel button">
<i class="remove icon"></i> {{.i18n.Tr "cloudbrain.operate_cancel"}}
</div>
<div class="ui green basic inverted ok button">
<i class="checkmark icon"></i> {{.i18n.Tr "cloudbrain.operate_confirm"}}
</div>
</div>
</div>
</div> </div>
</div>


</div> </div>
{{template "base/footer" .}} {{template "base/footer" .}}

<script>
$('.menu .item').tab()

$(document).ready(function(){
$('.ui.accordion').accordion({selector:{trigger:'.icon'}});
});
$(document).ready(function(){
$('.secondary.menu .item').tab();
});

let userName
let repoPath
let jobName
$(document).ready(function(){
let url = window.location.href;
let urlArr = url.split('/')
userName = urlArr.slice(-5)[0]
repoPath = urlArr.slice(-4)[0]
jobName = urlArr.slice(-1)[0]
})

function loadLog(version_name){
document.getElementById("mask").style.display = "block"
$.get(`/api/v1/repos/${userName}/${repoPath}/cloudbrain/${jobName}/log?version_name=${version_name}&lines=50&order=asc`, (data) => {
$('input[name=end_line]').val(data.EndLine)
$('input[name=start_line]').val(data.StartLine)
$(`#log_file${version_name}`).text(data.Content)
document.getElementById("mask").style.display = "none"
}).fail(function(err) {
console.log(err);
document.getElementById("mask").style.display = "none"
});
}

</script>

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

@@ -0,0 +1,443 @@
{{template "base/head" .}}
<style>

.unite{
font-family: SourceHanSansSC-medium !important;
color: rgba(16, 16, 16, 100) !important;
}

.title{
font-size: 16px !important;
padding-left: 3rem !important;
}
.min_title{
font-size: 14px !important;
padding-left: 6rem !important;
margin-bottom: 2rem !important;

}
.width{
width:100% !important;
}
.width80{
width: 80.7% !important;
margin-left: 10px;
}
.width806{
width: 80.6% !important;
margin-left: -2px;
}
.width85{
width: 85% !important;
margin-left: 4.5rem !important;
}
.width81{
margin-left: 1.5rem !important;
width: 81% !important;
}

.add{font-size: 18px;
padding: 0.5rem;
border: 1px solid rgba(187, 187, 187, 100);
border-radius: 0px 5px 5px 0px;
line-height: 21px;
text-align: center;
color: #C2C7CC;
}
.min{
font-size: 18px;
padding: 0.5rem;
border: 1px solid rgba(187, 187, 187, 100);
border-radius: 5px 0px 0px 5px;
line-height: 21px;
text-align: center;
color: #C2C7CC;
}

</style>
<!-- <div class="ui page dimmer">
<div class="ui text loader">{{.i18n.Tr "loading"}}</div>
</div> -->
<div id="mask">
<div id="loadingPage">
<div class="rect1"></div>
<div class="rect2"></div>
<div class="rect3"></div>
<div class="rect4"></div>
<div class="rect5"></div>
</div>
</div>
<div class="repository">
{{template "repo/header" .}}
<div class="ui container">
{{template "base/alert" .}}
<h4 class="ui top attached header">
{{.i18n.Tr "repo.modelarts.train_job.new"}}
</h4>
<div class="ui attached segment">
<!-- equal width -->
<form class="ui form" action="{{.Link}}" method="post">
{{.CsrfTokenHtml}}
<input type="hidden" name="action" value="update">
<input type="hidden" id="ai_engine_name" name="engine_names" value="">
<input type="hidden" id="ai_flaver_name" name="flaver_names" value="">
<h4 class="unite title ui header ">{{.i18n.Tr "repo.modelarts.train_job.basic_info"}}:</h4>
<div class="required unite min_title inline field">
<label style="font-weight: normal;">{{.i18n.Tr "cloudbrain.compute_resource"}}</label>
<div class="ui blue mini menu compact selectcloudbrain">
<a class="active item" href="{{.RepoLink}}/cloudbrain/train-job/create">
<svg class="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16">
<path fill="none" d="M0 0h24v24H0z"/>
<path d="M3 2.992C3 2.444 3.445 2 3.993 2h16.014a1 1 0 0 1 .993.992v18.016a.993.993 0 0 1-.993.992H3.993A1 1 0 0 1 3 21.008V2.992zM19 11V4H5v7h14zm0 2H5v7h14v-7zM9 6h6v2H9V6zm0 9h6v2H9v-2z"/>
</svg>
CPU/GPU
</a>
<a class="item" href="{{.RepoLink}}/modelarts/train-job/create">
<svg class="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16">
<path fill="none" d="M0 0h24v24H0z"/>
<path d="M3 2.992C3 2.444 3.445 2 3.993 2h16.014a1 1 0 0 1 .993.992v18.016a.993.993 0 0 1-.993.992H3.993A1 1 0 0 1 3 21.008V2.992zM19 11V4H5v7h14zm0 2H5v7h14v-7zM9 6h6v2H9V6zm0 9h6v2H9v-2z"/>
</svg>
Ascend NPU</a>
</div>
</div>
<div class="required unite min_title inline field">
<label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.job_name"}}</label>
<input style="width: 60%;" name="display_job_name" id="display_job_name" placeholder={{.i18n.Tr "repo.modelarts.train_job.job_name"}} value="{{.display_job_name}}" tabindex="3" onkeyup="this.value=this.value.replace(/[, ]/g,'')" autofocus required maxlength="64">
<span class="tooltips" style="display: block;">{{.i18n.Tr "cloudbrain.job_name_rule"}}</span>
</div>
<div class="unite min_title inline field">
<label style="font-weight: normal;" for="description">{{.i18n.Tr "repo.modelarts.train_job.description"}}&nbsp;&nbsp;</label>
<textarea style="width: 80%;" id="description" name="description" rows="3" maxlength="255" placeholder={{.i18n.Tr "repo.modelarts.train_job.new_place"}} onchange="this.value=this.value.substring(0, 255)" onkeydown="this.value=this.value.substring(0, 255)" onkeyup="this.value=this.value.substring(0, 255)"></textarea>
</div>
<div class="ui divider"></div>

<h4 class="unite title ui header ">{{.i18n.Tr "repo.modelarts.train_job.parameter_setting"}}:</h4>

<div class="required unite min_title inline field">
<label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.code_version"}}</label>
<select class="ui dropdown width80 left2" id="code_version" name="branch_name">
{{if .branch_name}}
<option name="branch_name" value="{{.branch_name}}">{{.branch_name}}</option>
{{range $k, $v :=.Branches}}
{{ if ne $v $.branch_name }}
<option name="branch_name" value="{{$v}}">{{$v}}</option>
{{end}}
{{end}}
{{else}}
<option name="branch_name" value="{{.branchName}}">{{.branchName}}</option>
{{range $k, $v :=.Branches}}
{{ if ne $v $.branchName }}
<option name="branch_name" value="{{$v}}">{{$v}}</option>
{{end}}
{{end}}
{{end}}
</select>
</div>

<div class="inline required field" style="display: none;">
<label>{{.i18n.Tr "cloudbrain.task_type"}}</label>
<select id="cloudbrain_job_type" class="ui search dropdown" placeholder="选择任务类型" style='width:385px' name="job_type">
<option name="job_type" value="TRAIN">TRAIN</option>
</select>
</div>

<div class="required unite min_title inline field">
<label style="font-weight: normal;">{{.i18n.Tr "cloudbrain.gpu_type"}}</label>
<select id="cloudbrain_gpu_type" class="ui search width806 dropdown" placeholder="选择GPU类型" style='width:385px' name="gpu_type">
{{range .train_gpu_types}}
<option value="{{.Queue}}">{{.Value}}</option>
{{end}}
</select>
</div>

<div class="required unite min_title inline field" style="position: relative;">
<label style="font-weight: normal;">{{.i18n.Tr "cloudbrain.mirror"}}&nbsp;</label>
<input class="width81" type="text" list="cloudbrain_image" placeholder="{{.i18n.Tr "cloudbrain.choose_mirror"}}" name="image" required autofocus maxlength="255">
<i class="times circle outline icon icons" style="visibility: hidden;" onclick="clearValue()"></i>
<datalist class="ui search" id="cloudbrain_image" name="image">
{{range .images}}
<option name="image" value="{{.Place}}">{{.PlaceView}}</option>
{{end}}
{{range .public_images}}
<option name="image" value="{{.Place}}">{{.PlaceView}}</option>
{{end}}
</datalist>
</div>

<div class="inline unite min_title field required">
<label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.start_file"}}</label>
{{if .bootFile}}
<input style="width: 35.5%;" name="boot_file" id="trainjob_boot_file" value="{{.bootFile}}" tabindex="3" autofocus required maxlength="255" >
{{else}}
<input style="width: 35.5%;" name="boot_file" id="trainjob_boot_file" value="" tabindex="3" autofocus required maxlength="255" >
{{end}}
<span>
<i class="question circle icon link" data-content={{.i18n.Tr "repo.modelarts.train_job.boot_file_helper"}} data-position="right center" data-variation="mini"></i>
</span>
<a href="https://git.openi.org.cn/OpenIOSSG/MNIST_PytorchExample_GPU" target="_blank">查看样例</a>
</div>

{{template "custom/select_dataset_train" .}}
<span class="tooltips" style="margin-left: 11.5rem;margin-bottom: 2rem;">训练脚本存储在/code中,数据集存储在/dataset中,训练输出请存储在/model中以供后续下载。</span>
<div class="inline unite min_title field">
<label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.run_parameter"}}</label>
<span id="add_run_para" style="margin-left: 0.5rem;cursor:pointer;color: rgba(3, 102, 214, 100);font-size: 14px;line-height: 26px;font-family: SourceHanSansSC-medium;"><i class="plus square outline icon"></i>{{.i18n.Tr "repo.modelarts.train_job.add_run_parameter"}}</span>
<input id="store_run_para" type="hidden" name="run_para_list">
<div class="dynamic field" style="margin-top: 1rem;">
{{if .params}}
{{if ne 0 (len .params)}}
{{range $k ,$v := .params}}
<div class="two fields width85" id="para{{$k}}">
<div class="field">
<input type="text" name="shipping_first-name" value={{$v.Label}} required>
</div>
<div class="field">
<input type="text" name="shipping_last-name" value={{$v.Value}} required>
</div>
<span>
<i class="trash icon"></i>
</span>

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

<div class="required inline unite min_title field">
<label style="font-weight: normal;">{{.i18n.Tr "cloudbrain.resource_specification"}}</label>
<select id="cloudbrain_resource_spec" class="ui search dropdown" placeholder="选择资源规格" style='width:385px' name="resource_spec_id">
{{range .train_resource_specs}}
<option name="resource_spec_id" value="{{.Id}}">GPU数:{{.GpuNum}},CPU数:{{.CpuNum}},内存(MB):{{.MemMiB}},共享内存(MB):{{.ShareMemMiB}}</option>
{{end}}
</select>
</div>
<div class="inline unite min_title field">
<button class="ui create_train_job green button">
{{.i18n.Tr "repo.cloudbrain.new"}}
</button>
<a class="ui button" href="{{.RepoLink}}/modelarts/train-job">{{.i18n.Tr "repo.cloudbrain.cancel"}}</a>
</div>
<!-- 模态框 -->
</form>
</div>
</div>
</div>
{{template "base/footer" .}}

<script>
//let url_href = window.location.pathname.split('create')[0]
//$(".ui.button").attr('href',url_href)
$('select.dropdown')
.dropdown();

$('.menu .item')
.tab();

let sever_num = $('#trainjob_work_server_num')
$('.add').click(function(){
sever_num.val(parseInt(sever_num.val())+1)
if(sever_num.val()>=26){
sever_num.val(parseInt(sever_num.val())-1)
}
})
$('.min').click(function(){
sever_num.val(parseInt(sever_num.val())-1)
if(sever_num.val()<=0){
sever_num.val(parseInt(sever_num.val())+1)
}
})
// 参数增加、删除、修改、保存
function Add_parameter(i){
value = '<div class="two fields width85" id= "para'+ i +'">' +
'<div class="field">' +
'<input type="text" name="shipping_first-name" required placeholder={{.i18n.Tr "repo.modelarts.train_job.parameter_name"}}> ' +
'</div> ' +
'<div class="field"> ' +
'<input type="text" name="shipping_last-name" required placeholder={{.i18n.Tr "repo.modelarts.train_job.parameter_value"}}>' +
'</div>'+
'<span>' +
'<i class="trash icon">' +
'</i>' +
'</span>' +
'</div>'
$(".dynamic.field").append(value)
}

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

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

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

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

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

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

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

function validate(){
$('.ui.form')
.form({
on: 'blur',
fields: {
boot_file: {
identifier : 'boot_file',
rules: [
{
type: 'regExp[/.+\.py$/g]',
}
]
},
display_job_name:{
identifier : 'display_job_name',
rules: [
{
type: 'regExp[/^[a-zA-Z0-9-_]{1,64}[a-zA-Z0-9_]$/]',
}
]
},
attachment:{
identifier : 'attachment',
rules: [
{
type: 'empty',
}
]

},
work_server_number: {
identifier : 'work_server_number',
rules: [
{
type : 'integer[1..25]',
}
]
}
},
onSuccess: function(){
// $('.ui.page.dimmer').dimmer('show')
document.getElementById("mask").style.display = "block"
},
onFailure: function(e){
return false;
}
})
}
document.onreadystatechange = function() {
if (document.readyState === "complete") {
document.getElementById("mask").style.display = "none"
}
}
function send_run_para(){
var run_parameters = []
var msg = {}
$(".dynamic.field .two.fields").each(function(){
var para_name = $(this).find('input[name=shipping_first-name]').val()
var para_value = $(this).find('input[name=shipping_last-name]').val()
run_parameters.push({"label": para_name, "value": para_value})
})
msg["parameter"] = run_parameters
msg = JSON.stringify(msg)
$('#store_run_para').val(msg)
}
function get_name(){
let name1=$("#engine_name .text").text()
let name2=$("#flaver_name .text").text()
$("input#ai_engine_name").val(name1)
$("input#ai_flaver_name").val(name2)

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

+ 653
- 0
templates/repo/cloudbrain/trainjob/show.tmpl View File

@@ -0,0 +1,653 @@
{{template "base/head" .}}
<style>
.according-panel-heading{
box-sizing: border-box;
padding: 8px 16px;
color: #252b3a;
background-color: #f2f5fc;
line-height: 1.5;
cursor: pointer;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
-khtml-user-select: none;
user-select: none;
}
.accordion-panel-title {
margin-top: 0;
margin-bottom: 0;
color: #252b3a;
}
.accordion-panel-title-content{
vertical-align: middle;
display: inline-block;
width: calc(100% - 32px);
cursor: default;
}
.acc-margin-bottom {
margin-bottom: 5px;
}
.title_text {
font-size: 12px;
}
.ac-display-inblock {
display: inline-block;
}
.cti-mgRight-sm {
margin-right: 8px;
}
.ac-text-normal {
font-size: 14px;
color: #575d6c;
}
.uc-accordionTitle-black {
color: #333;
}
.accordion-border{
border:1px solid #cce2ff;
}
.padding0{
padding: 0 !important;
}
.content-pad{
padding: 15px 35px;
}
.content-margin{
margin:10px 5px ;
}
.tab_2_content {
min-height: 360px;
margin-left: 10px;
}
.ac-grid {
display: block;
*zoom: 1;
}
.ac-grid-col {
float: left;
width: 100%;
}
.ac-grid-col2 .ac-grid-col {
width: 50%;
}
.ti-form {
text-align: left;
max-width: 100%;
vertical-align: middle;
}
.ti-form>tbody {
font-size: 12px;
}
.ti-form>tbody, .ti-form>tbody>tr {
vertical-align: inherit;
}
.ti-text-form-label {
padding-bottom: 20px;
padding-right: 20px;
color: #8a8e99;
font-size: 12px;
white-space: nowrap !important;
width: 80px;
line-height: 30px;
}
.ti-text-form-content{
line-height: 30px;
padding-bottom: 20px;
}
.ti-form>tbody>tr>td {
vertical-align: top;
white-space: normal;
}
td, th {
padding: 0;
}
.ac-grid-col .text-span {
width: 450px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.redo-color{
color: #3291F8;
}
.ti-action-menu-item:not(:last-child){
margin-right: 10px;
padding-right: 11px;
text-decoration: none!important;
color: #526ecc;
cursor: pointer;
display: inline-block;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
-khtml-user-select: none;
user-select: none;
position: relative;
}
.ti-action-menu-item:not(:last-child):after {
content: "";
display: inline-block;
position: absolute;
height: 12px;
right: 0;
top: 50%;
-webkit-transform: translateY(-6px);
-ms-transform: translateY(-6px);
-o-transform: translateY(-6px);
transform: translateY(-6px);
border-right: 1px solid #dfe1e6;
}
.text-width80{
width: 100px;
line-height: 30px;
}
.border-according{
border: 1px solid #dfe1e6;
}
.disabled {
cursor: default;
pointer-events: none;
color: rgba(0,0,0,.6) !important;
opacity: .45 !important;
}
.pad20{
border:0px !important;
}
.model_file_bread{
margin-bottom: -0.5rem !important;
padding-left: 1rem;
padding-top: 0.5rem ;
}
</style>
<div id="mask">
<div id="loadingPage">
<div class="rect1"></div>
<div class="rect2"></div>
<div class="rect3"></div>
<div class="rect4"></div>
<div class="rect5"></div>
</div>
</div>
<div class="repository">
{{template "repo/header" .}}
<div class="ui container">
<h4 class="ui header" id="vertical-segment">
<div class="ui breadcrumb">
<a class="section" href="{{.RepoLink}}/debugjob?debugListType=all">
{{.i18n.Tr "repo.cloudbrain"}}
</a>
<div class="divider"> / </div>
<a class="section" href="{{$.RepoLink}}/modelarts/train-job">
{{$.i18n.Tr "repo.modelarts.train_job"}}
</a>
<div class="divider"> / </div>
<div class="active section">{{.displayJobName}}</div>
</div>
</h4>
{{range $k ,$v := .version_list_task}}
<div class="ui accordion border-according" id="accordion{{.VersionName}}" data-repopath="{{$.RepoRelPath}}" data-jobid="{{.JobID}}" data-version="{{.VersionName}}">
<input type="hidden" id="jobId_input" name="jobId_input" value="{{.JobID}}">
<div class="{{if eq $k 0}}active{{end}} title padding0">
<div class="according-panel-heading">
<div class="accordion-panel-title">
<i class="dropdown icon"></i>
<span class="accordion-panel-title-content">
<span>
<div class="ac-display-inblock title_text acc-margin-bottom">
<span class="cti-mgRight-sm">{{TimeSinceUnix1 .CreatedUnix}}</span>
<span class="cti-mgRight-sm">{{$.i18n.Tr "repo.modelarts.status"}}:
<span id="{{.VersionName}}-status-span"><i id="icon" style="vertical-align: middle;" class="{{.Status}}"></i><span id="text" style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span>
</span>
<span class="cti-mgRight-sm">{{$.i18n.Tr "repo.modelarts.train_job.dura_time"}}:</span>
<span class="cti-mgRight-sm uc-accordionTitle-black" id="{{.VersionName}}-duration-span">{{$.duration}}</span>
</div>
</span>
</span>
</div>
</div>
</div>
<div class="{{if eq $k 0}}active{{end}} content">
<div class="content-pad">
<div class="ui pointing secondary menu" style="border-bottom: 1px solid rgba(34,36,38,.15);">
<a class="active item" data-tab="first{{$k}}">{{$.i18n.Tr "repo.modelarts.train_job.config"}}</a>
<a class="item" data-tab="second{{$k}}" onclick="loadLog({{.VersionName}})">{{$.i18n.Tr "repo.modelarts.log"}}</a>
<a class="item" data-tab="third{{$k}}" onclick="loadModelFile({{.VersionName}},'','','init')">{{$.i18n.Tr "repo.model_download"}}</a>
</div>
<div class="ui tab active" data-tab="first{{$k}}">
<div style="padding-top: 10px;">
<div class="tab_2_content">
<div class="ac-grid ac-grid-col2">
<div class="ac-grid-col">
<table class="ti-form">
<tbody class="ti-text-form">
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "repo.cloudbrain_task"}}
</td>
<td class="ti-text-form-content">
<div class="text-span text-span-w">
{{.DisplayJobName}}
</div>
</td>
</tr>
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "repo.modelarts.status"}}
</td>

<td class="ti-text-form-content">
<div class="text-span text-span-w" id="{{.VersionName}}-status">
{{.Status}}
</div>
</td>
</tr>
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "repo.modelarts.train_job.start_time"}}
</td>
<td class="ti-text-form-content">
<div class="text-span text-span-w">
<span style="font-size: 12px;" class="">{{TimeSinceUnix1 .CreatedUnix}}</span>
</div>
</td>
</tr>
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "repo.modelarts.train_job.dura_time"}}
</td>
<td class="ti-text-form-content">
<div class="text-span text-span-w" id="{{.VersionName}}-duration">
{{$.duration}}
</div>
</td>
</tr>
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "repo.modelarts.train_job.resource_type"}}
</td>
<td class="ti-text-form-content">
<div class="text-span text-span-w">
{{$.resource_type}}
</div>
</td>
</tr>
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "repo.modelarts.train_job.standard"}}
</td>
<td class="ti-text-form-content">
<div class="text-span text-span-w">
{{$.resource_spec}}
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div class="ac-grid-col">
<table class="ti-form">
<tbody class="ti-text-form">
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
镜像
</td>
<td class="ti-text-form-content">
<div class="text-span text-span-w" id="{{.VersionName}}-mirror">
{{.Image}}
</div>
</td>
</tr>
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "repo.modelarts.code_version"}}
</td>
<td class="ti-text-form-content">
<div class="text-span text-span-w">
{{.BranchName}}
</div>
</td>
</tr>

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

<td class="ti-text-form-content">
<div class="text-span text-span-w">
{{.BootFile}}
</div>
</td>
</tr>

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

<td class="ti-text-form-content">
<div class="text-span text-span-w">
{{.DatasetName}}
</div>
</td>
</tr>

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

<td class="ti-text-form-content">
<div class="text-span text-span-w" title="{{.Parameters}}">
{{.Parameters}}
</div>
</td>
</tr>

<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "repo.modelarts.train_job.description"}}
</td>
<td class="ti-text-form-content">
<div class="text-span text-span-w" title="{{.Description}}">
{{.Description}}
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<div class="ui tab" data-tab="second{{$k}}">
<div>
<div class="ui message message{{.VersionName}}" style="display: none;">
<div id="header"></div>
</div>
<div class="ui attached log" id="log{{.VersionName}}" style="height: 300px !important; overflow: auto;">
<input type="hidden" name="end_line" value>
<input type="hidden" name="start_line" value>
<pre id="log_file{{.VersionName}}"></pre>
</div>
</div>
</div>

<div class="ui tab" data-tab="third{{$k}}">
<input type="hidden" name="model{{.VersionName}}" value="-1">
<input type="hidden" name="modelback{{.VersionName}}" value="-1">
<div class='ui breadcrumb model_file_bread' id='file_breadcrumb{{.VersionName}}'>
<div class="active section">{{.VersionName}}</div>
<div class="divider"> / </div>

</div>
<div id="dir_list{{.VersionName}}">
</div>
</div>
</div>
</div>
</div>
{{end}} {{template "base/paginate" .}}
</div>
<!-- 确认模态框 -->
<div id="deletemodel">
<div class="ui basic modal">
<div class="ui icon header">
<i class="trash icon"></i> 删除任务
</div>
<div class="content">
<p>你确认删除该任务么?此任务一旦删除不可恢复。</p>
</div>
<div class="actions">
<div class="ui red basic inverted cancel button">
<i class="remove icon"></i> 取消操作
</div>
<div class="ui green basic inverted ok button">
<i class="checkmark icon"></i> 确定操作
</div>
</div>
</div>
</div>
</div>
{{template "base/footer" .}}

<script>
$('.menu .item').tab()

$(document).ready(function(){
$('.ui.accordion').accordion({selector:{trigger:'.icon'}});
});
$(document).ready(function(){
$('.secondary.menu .item').tab();
});
let userName
let repoPath
let jobID
let downlaodFlag = {{$.canDownload}}
let taskID = {{$.task.ID}}
let realJobName = {{$.task.JobName}}
$(document).ready(function(){
let url = window.location.href;
let urlArr = url.split('/')
userName = urlArr.slice(-5)[0]
repoPath = urlArr.slice(-4)[0]
jobID = urlArr.slice(-1)[0]
})
function stopBubbling(e) {
e = window.event || e;
if (e.stopPropagation) {
e.stopPropagation(); //阻止事件 冒泡传播
} else {
e.cancelBubble = true; //ie兼容
}
}
let timeid = window.setInterval(loadJobStatus, 30000);
$(document).ready(loadJobStatus);

function loadLog(version_name){
document.getElementById("mask").style.display = "block"
$.get(`/api/v1/repos/${userName}/${repoPath}/cloudbrain/${taskID}/log?version_name=${version_name}&lines=50&order=asc`, (data) => {
$('input[name=end_line]').val(data.EndLine)
$('input[name=start_line]').val(data.StartLine)
$(`#log_file${version_name}`).text(data.Content)
document.getElementById("mask").style.display = "none"
}).fail(function(err) {
console.log(err);
document.getElementById("mask").style.display = "none"
});
}
function loadModelFile(version_name,parents,filename,init){
parents = parents || ''
filename = filename || ''
init = init || ''
console.log("start")
$.get(`/api/v1/repos/${userName}/${repoPath}/cloudbrain/train-job/${jobID}/model_list?version_name=${version_name}&parentDir=${parents}`, (data) => {
$(`#dir_list${version_name}`).empty()
renderDir(data,version_name)
if(init==="init"){
$(`input[name=model${version_name}]`).val("")
$(`input[name=modelback${version_name}]`).val(version_name)
$(`#file_breadcrumb${version_name}`).empty()
let htmlBread = ""
htmlBread += `<div class='active section'>${version_name}</div>`
htmlBread += "<div class='divider'> / </div>"
$(`#file_breadcrumb${version_name}`).append(htmlBread)
}else{
renderBrend(version_name,parents,filename,init)
}
}).fail(function(err) {
console.log(err,version_name);
});
}
function renderBrend(version_name,parents,filename,init){
if(init=="folder"){
let htmlBrend = ""
let sectionName=$(`#file_breadcrumb${version_name} .active.section`).text()
let parents1 = $(`input[name=model${version_name}]`).val()
let filename1 = $(`input[name=modelback${version_name}]`).val()
if(parents1===""){
$(`#file_breadcrumb${version_name} .active.section`).replaceWith(`<a class='section' onclick="loadModelFile('${version_name}','${parents1}','','init')">${sectionName}</a>`)
}else{
$(`#file_breadcrumb${version_name} .active.section`).replaceWith(`<a class='section' onclick="loadModelFile('${version_name}','${parents1}','${filename1}')">${sectionName}</a>`)
}
htmlBrend += `<div class='active section'>${filename}</div>`
htmlBrend += "<div class='divider'> / </div>"
$(`#file_breadcrumb${version_name}`).append(htmlBrend)
$(`input[name=model${version_name}]`).val(parents)
$(`input[name=modelback${version_name}]`).val(filename)
}else{
$(`input[name=model${version_name}]`).val(parents)
$(`input[name=modelback${version_name}]`).val(filename)
$(`#file_breadcrumb${version_name} a.section:contains(${filename})`).nextAll().remove()
$(`#file_breadcrumb${version_name} a.section:contains(${filename})`).replaceWith(`<div class='active section'>${filename}</div>`)
$(`#file_breadcrumb${version_name} div.section:contains(${filename})`).append("<div class='divider'> / </div>")
}
}
function renderDir(data,version_name){
let html=""
html += "<div class='ui grid' style='margin:0;'>"
html += "<div class='row' style='padding: 0;'>"
html += "<div class='ui sixteen wide column' style='padding:1rem;'>"
html += "<div class='dir list'>"
html += "<table id='repo-files-table' class='ui single line table pad20'>"
html += '<tbody>'
// html += "</tbody>"
for(let i=0;i<data.Dirs.length;i++){
let dirs_size = renderSize(data.Dirs[i].Size)
html += "<tr>"
html += "<td class='name six wid'>"
html += "<span class='truncate'>"
html += "<span class='octicon octicon-file-directory'>"
html += "</span>"
if(data.Dirs[i].IsDir){
html += `<a onclick="loadModelFile('${version_name}','${data.Dirs[i].ParenDir}','${data.Dirs[i].FileName}','folder')">`
html += "<span class='fitted'><i class='folder icon' width='16' height='16' aria-hidden='true'></i>" + data.Dirs[i].FileName + "</span>"
}else{
if(downlaodFlag){
html += `<a href="${location.href}/download_model?version_name=${version_name}&fileName=${data.Dirs[i].FileName}&parentDir=${data.Dirs[i].ParenDir}&jobName=${realJobName}">`
}
else{
html += `<a class="disabled">`
}
html += "<span class='fitted'><i class='file icon' width='16' height='16' aria-hidden='true'></i>" + data.Dirs[i].FileName + "</span>"
}
html += '</a>'
html += "</span>"
html += "</td>"
html += "<td class='message seven wide'>"
if(data.Dirs[i].IsDir){
html += "<span class='truncate has-emoji'></span>"
}else{
html += "<span class='truncate has-emoji'>"+ `${dirs_size}` + "</span>"
}
html += "</td>"

html += "<td class='text right age three wide'>"
html += "<span class='truncate has-emoji'>" + data.Dirs[i].ModTime + "</span>"
html += "</td>"
html += "</tr>"
}
html += "</tbody>"
html += "</table>"
html += "</div>"
html += "</div>"
html += "</div>"
html += "</div>"
$(`#dir_list${version_name}`).append(html)
}
function renderSize(value){
if(null==value||value==''){
return "0 Bytes";
}
var unitArr = new Array("Bytes","KB","MB","GB","TB","PB","EB","ZB","YB");
var index=0;
var srcsize = parseFloat(value);
index=Math.floor(Math.log(srcsize)/Math.log(1024));
var size =srcsize/Math.pow(1024,index);
size=size.toFixed(0);//保留的小数位数
return size+unitArr[index];
}
function loadJobStatus() {
$(".ui.accordion.border-according").each((index, job) => {
const jobID = job.dataset.jobid;
const repoPath = job.dataset.repopath;
const versionname = job.dataset.version
// ['IMAGE_FAILED','SUBMIT_FAILED','DELETE_FAILED','KILLED','COMPLETED','FAILED','CANCELED','LOST','START_FAILED']
// if (job.textContent.trim() == 'IMAGE_FAILED' || job.textContent.trim() == 'SUBMIT_FAILED' || job.textContent.trim() == 'DELETE_FAILED'
// || job.textContent.trim() == 'KILLED' || job.textContent.trim() == 'COMPLETED' || job.textContent.trim() == 'FAILED'
// || job.textContent.trim() == 'CANCELED' || job.textContent.trim() == 'LOST') {
// return
// }
let status = $(`#${versionname}-status-span`).text()
if(['IMAGE_FAILED','SUBMIT_FAILED','DELETE_FAILED','KILLED','COMPLETED','FAILED','CANCELED','LOST','START_FAILED','SUCCEEDED'].includes(status)){
return
}
let stopArray=["KILLED","FAILED","START_FAILED","KILLING","COMPLETED","SUCCEEDED"]
$.get(`/api/v1/repos/${repoPath}/cloudbrain/${taskID}?version_name=${versionname}`, (data) => {
//$(`#${versionname}-duration-span`).text(data.JobDuration)
$(`#${versionname}-status-span span`).text(data.JobStatus)
$(`#${versionname}-status-span i`).attr("class",data.JobStatus)
// detail status and duration
//$('#'+versionname+'-duration').text(data.JobDuration)
$('#'+versionname+'-status').text(data.JobStatus)
if(stopArray.includes(data.JobStatus)){
$('#'+versionname+'-stop').addClass('disabled')
}
if(data.JobStatus==="COMPLETED"){
$('#'+versionname+'-create-model').removeClass('disabled').addClass('blue')
}
}).fail(function(err) {
console.log(err);
});
});
};

function refreshStatus(version_name){
$.get(`/api/v1/repos/${userName}/${repoPath}/cloudbrain/${taskID}?version_name=${versionname}`,(data)=>{
// header status and duration
//$(`#${version_name}-duration-span`).text(data.JobDuration)
$(`#${version_name}-status-span span`).text(data.JobStatus)
$(`#${version_name}-status-span i`).attr("class",data.JobStatus)
// detail status and duration
//$('#'+version_name+'-duration').text(data.JobDuration)
$('#'+version_name+'-status').text(data.JobStatus)
loadLog(version_name)


}).fail(function(err) {
console.log(err);
});
stopBubbling(arguments.callee.caller.arguments[0])
}
</script>

+ 6
- 6
templates/repo/datasets/index.tmpl View File

@@ -131,7 +131,7 @@
<a style="margin-left:30px;" href="{{.RepoLink}}/datasets/edit/{{.dataset.ID}}" class="ui primary basic mini {{if not $.CanWrite}} disabled {{end}} button">{{.i18n.Tr "repo.modelarts.modify"}}</a> <a style="margin-left:30px;" href="{{.RepoLink}}/datasets/edit/{{.dataset.ID}}" class="ui primary basic mini {{if not $.CanWrite}} disabled {{end}} button">{{.i18n.Tr "repo.modelarts.modify"}}</a>
</span> </span>
</div> </div>
{{if and (.dataset.Category) (.dataset.Task) (.dataset.License)}}
{{if or (.dataset.Category) (.dataset.Task) (.dataset.License)}}
<div class="column thirteen wide"> <div class="column thirteen wide">
{{if .dataset.Category}} {{if .dataset.Category}}
{{$category := .dataset.Category}} {{$category := .dataset.Category}}
@@ -199,7 +199,7 @@
</div> </div>
</div> </div>
{{range $k, $v :=.Attachments}} {{range $k, $v :=.Attachments}}
<div class="ui grid stackable item" id="{{.FileChunk.UUID}}">
<div class="ui grid stackable item" id="{{.UUID}}">
<div class="row"> <div class="row">
<!-- 数据集名称 --> <!-- 数据集名称 -->


@@ -266,8 +266,8 @@
<a class="ui basic blue button" href="datasets/dirs/{{.UUID}}?type={{$.Type}}" data-tooltip='{{$.i18n.Tr "dataset.directory"}}'>{{$.i18n.Tr "preview"}}</a> <a class="ui basic blue button" href="datasets/dirs/{{.UUID}}?type={{$.Type}}" data-tooltip='{{$.i18n.Tr "dataset.directory"}}'>{{$.i18n.Tr "preview"}}</a>
{{end}} {{end}}
{{if and (.CanDel) (not $.Repository.IsPrivate)}} {{if and (.CanDel) (not $.Repository.IsPrivate)}}
<span class="ui basic blue button" style="color: #13c28d !important;" @click="setPrivate('{{.FileChunk.UUID}}',false,{{$k}})" v-if="privates[{{$k}}]">{{$.i18n.Tr "dataset.set_public"}}</span>
<span class="ui basic blue button" style="color: #fa8c16 !important;" @click="setPrivate('{{.FileChunk.UUID}}',true,{{$k}})" v-else="privates[{{$k}}]">{{$.i18n.Tr "dataset.set_private"}}</span>
<span class="ui basic blue button" style="color: #13c28d !important;" @click="setPrivate('{{.UUID}}',false,{{$k}})" v-if="privates[{{$k}}]">{{$.i18n.Tr "dataset.set_public"}}</span>
<span class="ui basic blue button" style="color: #fa8c16 !important;" @click="setPrivate('{{.UUID}}',true,{{$k}})" v-else="privates[{{$k}}]">{{$.i18n.Tr "dataset.set_private"}}</span>
{{end}} {{end}}
<!-- {{if $.CanRead}} <!-- {{if $.CanRead}}
<a class="ui basic blue button" href="datasets/label/{{.UUID}}?type={{$.Type}}" data-tooltip='{{$.i18n.Tr "dataset.create_label_task"}}'>标注</a> <a class="ui basic blue button" href="datasets/label/{{.UUID}}?type={{$.Type}}" data-tooltip='{{$.i18n.Tr "dataset.create_label_task"}}'>标注</a>
@@ -281,13 +281,13 @@
</span> </span>
<el-dropdown-menu slot="dropdown"> <el-dropdown-menu slot="dropdown">
<el-dropdown-item class="clipboard" data-clipboard-text="{{.DownloadURL}}" data-clipboard-action="copy">{{$.i18n.Tr "dataset.copy_url"}}</el-dropdown-item> <el-dropdown-item class="clipboard" data-clipboard-text="{{.DownloadURL}}" data-clipboard-action="copy">{{$.i18n.Tr "dataset.copy_url"}}</el-dropdown-item>
<el-dropdown-item class="clipboard" data-clipboard-text="{{.FileChunk.Md5}}" data-clipboard-action="copy">{{$.i18n.Tr "dataset.copy_md5"}}</el-dropdown-item>
<el-dropdown-item class="clipboard" data-clipboard-text="{{.Md5}}" data-clipboard-action="copy">{{$.i18n.Tr "dataset.copy_md5"}}</el-dropdown-item>
{{if and ($.CanWrite) (eq .DecompressState 1) }} {{if and ($.CanWrite) (eq .DecompressState 1) }}
<el-dropdown-item @click.native="gotoAnnotate('{{$.RepoLink}}','{{.UUID}}',{{.Type}})">{{$.i18n.Tr "dataset.annotation"}}</el-dropdown-item> <el-dropdown-item @click.native="gotoAnnotate('{{$.RepoLink}}','{{.UUID}}',{{.Type}})">{{$.i18n.Tr "dataset.annotation"}}</el-dropdown-item>
{{end}} {{end}}
{{if .CanDel}} {{if .CanDel}}
<el-dropdown-item @click.native="gotoDatasetEidt('{{$.RepoLink}}',{{.ID}})">{{$.i18n.Tr "dataset.modify_description"}}</el-dropdown-item> <el-dropdown-item @click.native="gotoDatasetEidt('{{$.RepoLink}}',{{.ID}})">{{$.i18n.Tr "dataset.modify_description"}}</el-dropdown-item>
<el-dropdown-item style="color: red;" @click.native="delDataset('{{.FileChunk.UUID}}')">{{$.i18n.Tr "dataset.delete"}}</el-dropdown-item>
<el-dropdown-item style="color: red;" @click.native="delDataset('{{.UUID}}')">{{$.i18n.Tr "dataset.delete"}}</el-dropdown-item>
{{end}} {{end}}
</el-dropdown-menu> </el-dropdown-menu>
</el-dropdown> </el-dropdown>


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

@@ -443,7 +443,20 @@
</div> </div>
</div> </div>
</div> </div>
{{end}} {{template "base/paginate" .}}
{{end}}
<div id="app" style="margin-top: 2rem;">
<div class="center">
<el-pagination
background
@current-change="handleCurrentChange"
:current-page="page"
:page-sizes="[10]"
:page-size="10"
layout="total, sizes, prev, pager, next, jumper"
:total="{{.Page.Paginater.Total}}">
</el-pagination>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>


+ 14
- 1
templates/repo/modelarts/inferencejob/index.tmpl View File

@@ -186,7 +186,20 @@
</div> </div>
</div> </div>
</div> </div>
{{end}} {{template "base/paginate" .}}
{{end}}
<div id="app" style="margin-top: 2rem;">
<div class="center">
<el-pagination
background
@current-change="handleCurrentChange"
:current-page="page"
:page-sizes="[10]"
:page-size="10"
layout="total, sizes, prev, pager, next, jumper"
:total="{{.Page.Paginater.Total}}">
</el-pagination>
</div>
</div>
</div> </div>


</div> </div>


+ 3
- 17
templates/repo/modelarts/inferencejob/new.tmpl View File

@@ -169,24 +169,10 @@
</select> </select>
</div> </div>
<!-- 数据集 --> <!-- 数据集 -->
<div class="required unite min_title inline field">
<label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.dataset"}}</label>&nbsp;&nbsp;&nbsp;&nbsp;
<select class="ui dropdown width35" id="trainjob_datasets" name="attachment" placeholder="{{.i18n.Tr "cloudbrain.select_dataset"}}" required>
{{if $.uuid}}
<option name="attachment" value="{{$.uuid}}">{{$.datasetName}}</option>
{{end}}
{{range .attachments}}
<option value="">{{$.i18n.Tr "cloudbrain.select_dataset"}}</option>
<option name="attachment" value="{{.UUID}}">{{.Attachment.Name}}</option>
{{end}}
</select>
<span>
<i class="question circle icon" data-content="{{.i18n.Tr "cloudbrain.dataset_path_rule"}}" data-position="top center" data-variation="inverted mini"></i>
</span>
</div>
<!-- 启动文件 -->
{{template "custom/select_dataset_train" .}}
<span class="tooltips" style="margin-left: 11.5rem;margin-bottom: 2rem;">{{.i18n.Tr "cloudbrain.dataset_path_rule"}}</span>
<div class="inline unite min_title field required"> <div class="inline unite min_title field required">
<label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.start_file"}}</label>&nbsp;
<label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.start_file"}}</label>
{{if .bootFile}} {{if .bootFile}}
<input style="width: 35.5%;" name="boot_file" id="trainjob_boot_file" value="{{.bootFile}}" tabindex="3" autofocus required maxlength="255" > <input style="width: 35.5%;" name="boot_file" id="trainjob_boot_file" value="{{.bootFile}}" tabindex="3" autofocus required maxlength="255" >
{{else}} {{else}}


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

@@ -232,7 +232,13 @@ td, th {


<td class="ti-text-form-content"> <td class="ti-text-form-content">
<div class="text-span text-span-w"> <div class="text-span text-span-w">
<span style="font-size: 12px;" class="">{{TimeSinceUnix1 .CreatedUnix}}</span>
<span style="font-size: 12px;" class="">
{{if not (eq .StartTime 0)}}
{{TimeSinceUnix1 .StartTime}}
{{else}}
{{TimeSinceUnix1 .CreatedUnix}}
{{end}}
</span>
</div> </div>
</td> </td>
</tr> </tr>


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

@@ -59,21 +59,7 @@
{{end}} {{end}}
</select> </select>
</div> </div>
<<<<<<< HEAD
{{template "custom/select_dataset" .}} {{template "custom/select_dataset" .}}
=======

<div class="inline field">
<label>{{.i18n.Tr "cloudbrain.dataset"}}</label>
<input type="text" list="cloudbrain_dataset" placeholder="{{.i18n.Tr "cloudbrain.select_dataset"}}" name="" id="answerInput" autofocus maxlength="36">
<datalist id="cloudbrain_dataset" class="ui search" style='width:385px' name="attachment">
{{range .attachments}}
<option name="attachment" data-value="{{.UUID}}">{{.Attachment.Name}}</option>
{{end}}
</datalist>
<input type="hidden" name="attachment" id="answerInput-hidden">
</div>
>>>>>>> V20220328


<!--<div class="inline required field"> <!--<div class="inline required field">
<label>工作环境</label> <label>工作环境</label>


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

@@ -1,68 +1,442 @@
{{template "base/head" .}} {{template "base/head" .}}
<style>
.according-panel-heading{
box-sizing: border-box;
padding: 8px 16px;
color: #252b3a;
background-color: #f2f5fc;
line-height: 1.5;
cursor: pointer;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
-khtml-user-select: none;
user-select: none;
}
.accordion-panel-title {
margin-top: 0;
margin-bottom: 0;
color: #252b3a;
}
.accordion-panel-title-content{
vertical-align: middle;
display: inline-block;
width: calc(100% - 32px);
cursor: default;
}
.acc-margin-bottom {
margin-bottom: 5px;
}
.title_text {
font-size: 12px;
}
.ac-display-inblock {
display: inline-block;
}
.cti-mgRight-sm {
margin-right: 8px;
}
.ac-text-normal {
font-size: 14px;
color: #575d6c;
}
.uc-accordionTitle-black {
color: #333;
}
.accordion-border{
border:1px solid #cce2ff;
}
.padding0{
padding: 0 !important;
}
.content-pad{
padding: 15px 35px;
}
.content-margin{
margin:10px 5px ;
}
.tab_2_content {
min-height: 460px;
margin-left: 10px;
}
.ac-grid {
display: block;
*zoom: 1;
}
.ac-grid-col {
float: left;
width: 100%;
}
.ac-grid-col2 .ac-grid-col {
width: 50%;
}
.ti-form {
text-align: left;
max-width: 100%;
vertical-align: middle;
}
.ti-form>tbody {
font-size: 12px;
}
.ti-form>tbody, .ti-form>tbody>tr {
vertical-align: inherit;
}
.info_text {
padding-bottom: 20px;
padding-right: 20px;
font-size: 12px;
}

.ti-text-form-label {

padding-bottom: 20px;
padding-right: 20px;
color: #8a8e99;
font-size: 12px;
white-space: nowrap !important;
width: 80px;
line-height: 30px;
}
.ti-text-form-content{
line-height: 30px;
padding-bottom: 20px;
}
.ti-form>tbody>tr>td {
vertical-align: top;
white-space: normal;
}
td, th {
padding: 0;
}
.ac-grid-col .text-span {
width: 450px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.redo-color{
color: #3291F8;
}
.ti-action-menu-item:not(:last-child){
margin-right: 10px;
padding-right: 11px;
text-decoration: none!important;
color: #526ecc;
cursor: pointer;
display: inline-block;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
-khtml-user-select: none;
user-select: none;
position: relative;
}
.ti-action-menu-item:not(:last-child):after {
content: "";
display: inline-block;
position: absolute;
height: 12px;
right: 0;
top: 50%;
-webkit-transform: translateY(-6px);
-ms-transform: translateY(-6px);
-o-transform: translateY(-6px);
transform: translateY(-6px);
border-right: 1px solid #dfe1e6;
}
.text-width80{
width: 100px;
line-height: 30px;
}
.border-according{
border: 1px solid #dfe1e6;
}
.disabled {
cursor: default;
pointer-events: none;
color: rgba(0,0,0,.6) !important;
opacity: .45 !important;
}
.pad20{

border:0px !important;
}
.model_file_bread{
margin-bottom: -0.5rem !important;
padding-left: 1rem;
padding-top: 0.5rem ;
}
</style>
<div id="mask">
<div id="loadingPage">
<div class="rect1"></div>
<div class="rect2"></div>
<div class="rect3"></div>
<div class="rect4"></div>
<div class="rect5"></div>
</div>
</div>
<div class="repository"> <div class="repository">
{{template "repo/header" .}} {{template "repo/header" .}}
<div class="repository new repo ui middle very relaxed page grid">
<div class="column">
{{template "base/alert" .}}

<div class="ui container">
<h4 class="ui header" id="vertical-segment"> <h4 class="ui header" id="vertical-segment">
<div class="ui breadcrumb"> <div class="ui breadcrumb">
<a class="section" href="{{.RepoLink}}/debugjob?debugListType=all">
{{.i18n.Tr "repo.cloudbrain"}}
</a>
<div class="divider"> / </div>
<a class="section backTodeBug" href="{{.RepoLink}}/debugjob?debugListType={{if eq $.debugListType "NPU"}}NPU{{else if eq $.debugListType "CPU/GPU"}}CPU/GPU{{else}}all{{end}}">
<a class="section" href="{{.RepoLink}}/debugjob?debugListType=all">
{{.i18n.Tr "repo.cloudbrain"}}
</a>
<div class="divider"> / </div>
<a class="section backTodeBug" href="{{.RepoLink}}/debugjob?debugListType={{if eq $.debugListType "NPU"}}NPU{{else if eq $.debugListType "CPU/GPU"}}CPU/GPU{{else}}all{{end}}">
{{$.i18n.Tr "repo.modelarts.notebook"}} {{$.i18n.Tr "repo.modelarts.notebook"}}
</a>
<div class="divider"> / </div>
{{with .task}}
<div class="active section">{{.DisplayJobName}}</div>
{{end}}
</div>
</a>
<div class="divider"> / </div>
{{with .task}}
<div class="active section">{{.DisplayJobName}}</div>
{{end}}
</div>
</h4> </h4>
<div>
<div class="ui yellow segment">
{{with .task}}
<p>任务名称: {{.DisplayJobName}}</p>
{{end}}
</div>
<div class="ui green segment">
<p>任务详情:</p>
{{with .result}}
<table class="ui celled striped table">
<tbody>
<tr>
<td class="four wide"> 状态 </td>
<td> {{.Status}} </td>
</tr>
<tr>
<td> 描述 </td>
<td style="max-width: 480px; word-wrap:break-word">{{$.task.Description}}</td>
</tr>
<tr>
<td> 镜像名称 </td>
<td>{{$.task.Image}}</td>
</tr>
<tr>
<td> 数据集下载地址 </td>
<td style="max-width: 480px; word-wrap:break-word">{{$.datasetDownloadLink}}</td>
</tr>
<tr>
<td> 开始时间 </td>
<td>{{.CreateTime}}</td>
</tr>
<tr>
<td> 最后更新时间 </td>
<td>{{.LatestUpdateTime}}</td>
</tr>
</tbody>
</table>
{{end}}
</div>
{{with .task}}
<div class="ui accordion border-according" id="accordion" data-repopath="" data-jobid="" data-version="">
<div class="active title padding0">
<div class="according-panel-heading">
<div class="accordion-panel-title">
<i class="dropdown icon"></i>
<span class="accordion-panel-title-content">
<span>
<div class="ac-display-inblock title_text acc-margin-bottom">
<span class="cti-mgRight-sm">
{{if not (eq .StartTime 0)}}
<td>{{TimeSinceUnix1 .StartTime}}</td>
{{else}}
<td>{{TimeSinceUnix1 .CreatedUnix}}<td>
{{end}}
</span>

<span class="cti-mgRight-sm">{{$.i18n.Tr "repo.modelarts.status"}}:
<span id="{{.VersionName}}-status-span"><i id="icon" style="vertical-align: middle;" class="{{.Status}}"></i><span id="text" style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span>
</span>
<span class="cti-mgRight-sm">{{$.i18n.Tr "repo.modelarts.train_job.dura_time"}}:</span>
<span class="cti-mgRight-sm uc-accordionTitle-black" id="{{.VersionName}}-duration-span">{{$.duration}}</span>

</div>
</span>
</span>
</div>
</div>
</div>
<div class="active content">
<div class="content-pad">
<div class="ui pointing secondary menu" style="border-bottom: 1px solid rgba(34,36,38,.15);">
<a class="active item" data-tab="first">{{$.i18n.Tr "repo.modelarts.train_job.config"}}</a>
</div>
<div class="ui tab active" data-tab="first">
<div style="padding-top: 10px;">
<div class="tab_2_content">
<div class="ac-grid ac-grid-col2">
<div class="ac-grid-col">
<table class="ti-form">
<tbody class="ti-text-form">
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "repo.cloudbrain_task"}}
</td>
<td class="ti-text-form-content">
<div class="text-span text-span-w">
{{.DisplayJobName}}
</div>
</td>
</tr>
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "repo.modelarts.status"}}
</td>

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

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

<td class="ti-text-form-content">
<div class="text-span text-span-w">
<span style="font-size: 12px;" class="">
{{if not (eq .StartTime 0)}}
{{TimeSinceUnix1 .StartTime}}
{{else}}
{{TimeSinceUnix1 .CreatedUnix}}
{{end}}
</span>
</div>
</td>
</tr>

<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "admin.auths.updated"}}
</td>

<td class="ti-text-form-content">
<div class="text-span text-span-w" id="updateTime">
{{if not (eq .EndTime 0)}}
{{TimeSinceUnix1 .EndTime}}
{{else}}
{{TimeSinceUnix1 .UpdatedUnix}}
{{end}}
</div>
</td>
</tr>

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

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

</tbody>
</table>
</div>
<div class="ac-grid-col">
<table class="ti-form">
<tbody class="ti-text-form">

<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "cloudbrain.mirror"}}
</td>

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

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

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


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

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

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

<td class="ti-text-form-content">
<div class="text-span text-span-w" id="{{.VersionName}}-mirror">
{{.User.Name}}
</div>
</td>
</tr>
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "cloudbrain.description"}}
</td>

<td class="ti-text-form-content">
<div class="text-span text-span-w" id="model_storage_path">
{{.Description}}
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>

</div>
</div>

</div>
</div>
</div> </div>
{{end}}
{{template "base/paginate" .}}
</div>
<!-- 确认模态框 -->
<div id="deletemodel">
<div class="ui basic modal">
<div class="ui icon header">
<i class="trash icon"></i> {{.i18n.Tr "cloudbrain.delete_task"}}
</div>


<div class="content">
<p>{{.i18n.Tr "cloudbrain.task_delete_confirm"}}</p>
</div>
<div class="actions">
<div class="ui red basic inverted cancel button">
<i class="remove icon"></i> {{.i18n.Tr "cloudbrain.operate_cancel"}}
</div>
<div class="ui green basic inverted ok button">
<i class="checkmark icon"></i> {{.i18n.Tr "cloudbrain.operate_confirm"}}
</div>
</div>
</div>
</div> </div>
</div>


</div> </div>
{{template "base/footer" .}} {{template "base/footer" .}}

<script>
$('.menu .item').tab()

$(document).ready(function(){
$('.ui.accordion').accordion({selector:{trigger:'.icon'}});
});
$(document).ready(function(){
$('.secondary.menu .item').tab();
});

let userName
let repoPath
let jobName
$(document).ready(function(){
let url = window.location.href;
let urlArr = url.split('/')
userName = urlArr.slice(-5)[0]
repoPath = urlArr.slice(-4)[0]
jobName = urlArr.slice(-1)[0]
})


</script>

+ 53
- 5
templates/repo/modelarts/trainjob/index.tmpl View File

@@ -39,8 +39,18 @@
</div> </div>
</div> </div>
<div class="column right aligned"> <div class="column right aligned">
<div class="ui selection dropdown" style="min-width: 10em;min-height:2.6em;border-radius: .28571429rem;margin-right: 1em;padding: .67em 3.2em .7em 1em;">
{{svg "octicon-server" 16}}
<div class="default text" style="color: rgba(0,0,0,.87);"></div>
<i class="dropdown icon"></i>
<div class="menu">
<div class="item" data-value="all">{{$.i18n.Tr "repo.gpu_type_all"}}</div>
<div class="item" data-value="CPU/GPU">CPU/GPU</div>
<div class="item" data-value="NPU">NPU</div>
</div>
</div>
{{if .Permission.CanWrite $.UnitTypeCloudBrain}} {{if .Permission.CanWrite $.UnitTypeCloudBrain}}
<a class="ui green button" href="{{.RepoLink}}/modelarts/train-job/create">{{$.i18n.Tr "repo.modelarts.train_job.new_train"}}</a>
<a class="ui green button" href="{{.RepoLink}}/cloudbrain/train-job/create">{{$.i18n.Tr "repo.modelarts.train_job.new_train"}}</a>
{{else}} {{else}}
<a class="ui disabled button" >{{$.i18n.Tr "repo.modelarts.train_job.new_train"}}</a> <a class="ui disabled button" >{{$.i18n.Tr "repo.modelarts.train_job.new_train"}}</a>
{{end}} {{end}}
@@ -102,7 +112,7 @@


<!-- 任务名 --> <!-- 任务名 -->
<div class="three wide column padding0"> <div class="three wide column padding0">
<a class="title" href="{{$.Link}}/{{.JobID}}" title="{{.DisplayJobName}}" style="font-size: 14px;">
<a class="title" href='{{if eq .ComputeResource "NPU" }}{{$.Link}}/{{.JobID}}{{else}}{{$.RepoLink}}/cloudbrain/train-job/{{.JobID}}{{end}}' title="{{.DisplayJobName}}" style="font-size: 14px;">


<span class="fitted" style="width: 90%;vertical-align: middle;">{{.DisplayJobName}}</span> <span class="fitted" style="width: 90%;vertical-align: middle;">{{.DisplayJobName}}</span>
</a> </a>
@@ -143,7 +153,7 @@
<div class="ui compact buttons"> <div class="ui compact buttons">
{{$.CsrfTokenHtml}} {{$.CsrfTokenHtml}}
{{if .CanDel}} {{if .CanDel}}
<a style="padding: 0.5rem 1rem;" id="ai-stop-{{.JobID}}" class="ui basic ai_stop_version {{if eq .Status "KILLED" "FAILED" "START_FAILED" "KILLING" "COMPLETED"}}disabled {{else}} blue {{end}}button" data-repopath="{{$.RepoRelPath}}/modelarts/train-job" data-jobid="{{.JobID}}" data-version="{{.VersionName}}">
<a style="padding: 0.5rem 1rem;" id="ai-stop-{{.JobID}}" class="ui basic ai_stop_version {{if eq .Status "KILLED" "FAILED" "START_FAILED" "KILLING" "COMPLETED" "SUCCEEDED" "STOPPED"}}disabled {{else}} blue {{end}}button" data-repopath='{{$.RepoRelPath}}{{if eq .ComputeResource "NPU"}}/modelarts/train-job{{else}}/cloudbrain/train-job{{end}}' data-jobid="{{.JobID}}" data-version="{{.VersionName}}">
{{$.i18n.Tr "repo.stop"}} {{$.i18n.Tr "repo.stop"}}
</a> </a>
{{else}} {{else}}
@@ -154,7 +164,8 @@


</div> </div>
<!-- 删除任务 --> <!-- 删除任务 -->
<form class="ui compact buttons" id="delForm-{{.JobID}}" action="{{$.Link}}/{{.JobID}}/del" method="post">
<form class="ui compact buttons" id="delForm-{{.JobID}}" action='{{if eq .ComputeResource "NPU" }}{{$.Link}}/{{.JobID}}{{else}}{{$.RepoLink}}/cloudbrain/train-job/{{.JobID}}{{end}}/del' method="post">
<input type="hidden" name="listType" value="{{$.ListType}}">
{{$.CsrfTokenHtml}} {{$.CsrfTokenHtml}}
{{if .CanDel}} {{if .CanDel}}
<a style="padding: 0.5rem 1rem;margin-left:0.2rem" id="ai-delete-{{.JobID}}" class="ui basic ai_delete blue button" style="border-radius: .28571429rem;"> <a style="padding: 0.5rem 1rem;margin-left:0.2rem" id="ai-delete-{{.JobID}}" class="ui basic ai_delete blue button" style="border-radius: .28571429rem;">
@@ -169,7 +180,20 @@
</div> </div>
</div> </div>
</div> </div>
{{end}} {{template "base/paginate" .}}
{{end}}
<div id="app" style="margin-top: 2rem;">
<div class="center">
<el-pagination
background
@current-change="handleCurrentChange"
:current-page="page"
:page-sizes="[10]"
:page-size="10"
layout="total, sizes, prev, pager, next, jumper"
:total="{{.Page.Paginater.Total}}">
</el-pagination>
</div>
</div>
</div> </div>


</div> </div>
@@ -206,3 +230,27 @@
</div> </div>
</div> </div>
{{template "base/footer" .}} {{template "base/footer" .}}

<script>
let url = {{$.RepoLink}};
let all = {{$.i18n.Tr "repo.gpu_type_all"}}
$(document).ready(function(){
const params = new URLSearchParams(location.search)
if(!location.search){
$('.default.text').text(all)
}else{
if(params.has('listType') && params.get('listType')=='all'){
$('.default.text').text(all)
}
else{
$('.default.text').text(params.get('listType'))
}
}

$('.ui.selection.dropdown').dropdown({
onChange:function(value){
location.href = `${url}/modelarts/train-job?listType=${value}`
}
})
})
</script>

+ 24
- 17
templates/repo/modelarts/trainjob/new.tmpl View File

@@ -78,6 +78,24 @@
<input type="hidden" id="ai_engine_name" name="engine_names" value=""> <input type="hidden" id="ai_engine_name" name="engine_names" value="">
<input type="hidden" id="ai_flaver_name" name="flaver_names" value=""> <input type="hidden" id="ai_flaver_name" name="flaver_names" value="">
<h4 class="unite title ui header ">{{.i18n.Tr "repo.modelarts.train_job.basic_info"}}:</h4> <h4 class="unite title ui header ">{{.i18n.Tr "repo.modelarts.train_job.basic_info"}}:</h4>
<div class="required unite min_title inline field">
<label style="font-weight: normal;">{{.i18n.Tr "cloudbrain.compute_resource"}}</label>
<div class="ui blue mini menu compact selectcloudbrain">
<a class="item" href="{{.RepoLink}}/cloudbrain/train-job/create">
<svg class="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16">
<path fill="none" d="M0 0h24v24H0z"/>
<path d="M3 2.992C3 2.444 3.445 2 3.993 2h16.014a1 1 0 0 1 .993.992v18.016a.993.993 0 0 1-.993.992H3.993A1 1 0 0 1 3 21.008V2.992zM19 11V4H5v7h14zm0 2H5v7h14v-7zM9 6h6v2H9V6zm0 9h6v2H9v-2z"/>
</svg>
CPU/GPU
</a>
<a class="active item" href="{{.RepoLink}}/modelarts/train-job/create">
<svg class="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16">
<path fill="none" d="M0 0h24v24H0z"/>
<path d="M3 2.992C3 2.444 3.445 2 3.993 2h16.014a1 1 0 0 1 .993.992v18.016a.993.993 0 0 1-.993.992H3.993A1 1 0 0 1 3 21.008V2.992zM19 11V4H5v7h14zm0 2H5v7h14v-7zM9 6h6v2H9V6zm0 9h6v2H9v-2z"/>
</svg>
Ascend NPU</a>
</div>
</div>
<div class="required unite min_title inline field"> <div class="required unite min_title inline field">
<label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.job_name"}}</label> <label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.job_name"}}</label>
<input style="width: 60%;" name="display_job_name" id="display_job_name" placeholder={{.i18n.Tr "repo.modelarts.train_job.job_name"}} value="{{.display_job_name}}" tabindex="3" onkeyup="this.value=this.value.replace(/[, ]/g,'')" autofocus required maxlength="64"> <input style="width: 60%;" name="display_job_name" id="display_job_name" placeholder={{.i18n.Tr "repo.modelarts.train_job.job_name"}} value="{{.display_job_name}}" tabindex="3" onkeyup="this.value=this.value.replace(/[, ]/g,'')" autofocus required maxlength="64">
@@ -140,29 +158,18 @@
<div class="inline unite min_title field required"> <div class="inline unite min_title field required">
<label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.start_file"}}</label> <label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.start_file"}}</label>
{{if .bootFile}} {{if .bootFile}}
<input style="width: 33.5%;" name="boot_file" id="trainjob_boot_file" value="{{.bootFile}}" tabindex="3" autofocus required maxlength="255" >
<input style="width: 35.5%;" name="boot_file" id="trainjob_boot_file" value="{{.bootFile}}" tabindex="3" autofocus required maxlength="255" >
{{else}} {{else}}
<input style="width: 33.5%;" name="boot_file" id="trainjob_boot_file" value="" tabindex="3" autofocus required maxlength="255" >
<input style="width: 35.5%;" name="boot_file" id="trainjob_boot_file" value="" tabindex="3" autofocus required maxlength="255" >
{{end}} {{end}}
<span> <span>
<i class="question circle icon link" data-content={{.i18n.Tr "repo.modelarts.train_job.boot_file_helper"}} data-position="right center" data-variation="mini"></i> <i class="question circle icon link" data-content={{.i18n.Tr "repo.modelarts.train_job.boot_file_helper"}} data-position="right center" data-variation="mini"></i>
</span> </span>
<a href="https://git.openi.org.cn/OpenIOSSG/MINIST_Example" target="_blank">{{.i18n.Tr "cloudbrain.view_sample"}}</a> <a href="https://git.openi.org.cn/OpenIOSSG/MINIST_Example" target="_blank">{{.i18n.Tr "cloudbrain.view_sample"}}</a>
</div> </div>
<div class="required unite min_title inline field">
<label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.dataset"}}</label>
<select class="ui dropdown width80" id="trainjob_datasets" name="attachment" placeholder="{{.i18n.Tr "cloudbrain.select_dataset"}}">
{{if $.uuid}}
<option name="attachment" value="{{$.uuid}}">{{$.datasetName}}</option>
{{end}}
{{range .attachments}}
<option value="">{{$.i18n.Tr "cloudbrain.select_dataset"}}</option>
<option name="attachment" value="{{.UUID}}">{{.Attachment.Name}}</option>
{{end}}
</select>
<span class="tooltips">{{.i18n.Tr "cloudbrain.dataset_path_rule"}}</span>
</div>

{{template "custom/select_dataset_train" .}}
<span class="tooltips" style="margin-left: 11.5rem;margin-bottom: 2rem;">{{.i18n.Tr "cloudbrain.dataset_path_rule"}}</span>
<div class="inline unite min_title field"> <div class="inline unite min_title field">
<label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.run_parameter"}}</label> <label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.run_parameter"}}</label>
<span id="add_run_para" style="margin-left: 0.5rem;cursor:pointer;color: rgba(3, 102, 214, 100);font-size: 14px;line-height: 26px;font-family: SourceHanSansSC-medium;"><i class="plus square outline icon"></i>{{.i18n.Tr "repo.modelarts.train_job.add_run_parameter"}}</span> <span id="add_run_para" style="margin-left: 0.5rem;cursor:pointer;color: rgba(3, 102, 214, 100);font-size: 14px;line-height: 26px;font-family: SourceHanSansSC-medium;"><i class="plus square outline icon"></i>{{.i18n.Tr "repo.modelarts.train_job.add_run_parameter"}}</span>
@@ -395,7 +402,7 @@
identifier : 'display_job_name', identifier : 'display_job_name',
rules: [ rules: [
{ {
type: 'regExp[/^[a-zA-Z0-9-_]{1,64}[^-]$/]',
type: 'regExp[/^[a-zA-Z0-9-_]{1,64}[a-zA-Z0-9_]$/]',
} }
] ]
}, },


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

@@ -223,7 +223,12 @@ td, th {
</div> </div>
<div class="ac-display-inblock title_text acc-margin-bottom"> <div class="ac-display-inblock title_text acc-margin-bottom">


<span class="cti-mgRight-sm">{{TimeSinceUnix1 .Cloudbrain.CreatedUnix}}</span>
<span class="cti-mgRight-sm">
{{if not (eq .Cloudbrain.StartTime 0)}}
{{TimeSinceUnix1 .Cloudbrain.StartTime}}
{{else}}
{{TimeSinceUnix1 .Cloudbrain.CreatedUnix}}
{{end}}</span>
<span class="cti-mgRight-sm"> {{$.i18n.Tr "repo.modelarts.current_version"}}:{{.VersionName}}</span> <span class="cti-mgRight-sm"> {{$.i18n.Tr "repo.modelarts.current_version"}}:{{.VersionName}}</span>
<span class="cti-mgRight-sm"> {{$.i18n.Tr "repo.modelarts.parent_version"}}:{{.PreVersionName}}</span> <span class="cti-mgRight-sm"> {{$.i18n.Tr "repo.modelarts.parent_version"}}:{{.PreVersionName}}</span>
<span class="cti-mgRight-sm">{{$.i18n.Tr "repo.modelarts.status"}}: <span class="cti-mgRight-sm">{{$.i18n.Tr "repo.modelarts.status"}}:
@@ -293,7 +298,12 @@ td, th {


<td class="ti-text-form-content"> <td class="ti-text-form-content">
<div class="text-span text-span-w"> <div class="text-span text-span-w">
<span style="font-size: 12px;" class="">{{TimeSinceUnix1 .Cloudbrain.CreatedUnix}}</span>
<span style="font-size: 12px;" class="">
{{if not (eq .Cloudbrain.StartTime 0)}}
{{TimeSinceUnix1 .Cloudbrain.StartTime}}
{{else}}
{{TimeSinceUnix1 .Cloudbrain.CreatedUnix}}
{{end}}</span>
</div> </div>
</td> </td>
</tr> </tr>


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

@@ -40,7 +40,7 @@
<div class="ui right file-actions"> <div class="ui right file-actions">
{{if .Repository.CanEnableEditor}} {{if .Repository.CanEnableEditor}}
{{if .CanEditFile}} {{if .CanEditFile}}
<a href="{{.RepoLink}}/_edit/{{EscapePound .BranchName}}/{{EscapePound .ReadmeName}}"><span class="btn-octicon poping up" data-content="{{.EditFileTooltip}}" data-position="bottom center" data-variation="tiny inverted">{{svg "octicon-pencil" 16}}</span></a>
<a href="{{.RepoLink}}/_edit/{{EscapePound .BranchName}}/{{EscapePound .ReadmeRelativePath}}"><span class="btn-octicon poping up" data-content="{{.EditFileTooltip}}" data-position="bottom center" data-variation="tiny inverted">{{svg "octicon-pencil" 16}}</span></a>
{{else}} {{else}}
<span class="btn-octicon poping up disabled" data-content="{{.EditFileTooltip}}" data-position="bottom center" data-variation="tiny inverted">{{svg "octicon-pencil" 16}}</span> <span class="btn-octicon poping up disabled" data-content="{{.EditFileTooltip}}" data-position="bottom center" data-variation="tiny inverted">{{svg "octicon-pencil" 16}}</span>
{{end}} {{end}}
@@ -48,7 +48,7 @@
</div> </div>
</div> </div>
{{end}} {{end}}
{{if not .ReadmeInList}} {{if not .ReadmeInList}}
<div class="file-header-right"> <div class="file-header-right">
<div class="ui right file-actions"> <div class="ui right file-actions">


+ 5
- 1
templates/user/dashboard/feeds.tmpl View File

@@ -77,13 +77,15 @@
{{else if eq .GetOpType 26}} {{else if eq .GetOpType 26}}
{{$.i18n.Tr "action.task_npudebugjob" .GetRepoLink .Content .RefName | Str2html}} {{$.i18n.Tr "action.task_npudebugjob" .GetRepoLink .Content .RefName | Str2html}}
{{else if eq .GetOpType 27}} {{else if eq .GetOpType 27}}
{{$.i18n.Tr "action.task_trainjob" .GetRepoLink .Content .RefName | Str2html}}
{{$.i18n.Tr "action.task_nputrainjob" .GetRepoLink .Content .RefName | Str2html}}
{{else if eq .GetOpType 28}} {{else if eq .GetOpType 28}}
{{$.i18n.Tr "action.task_inferencejob" .GetRepoLink .Content .RefName | Str2html}} {{$.i18n.Tr "action.task_inferencejob" .GetRepoLink .Content .RefName | Str2html}}
{{else if eq .GetOpType 29}} {{else if eq .GetOpType 29}}
{{$.i18n.Tr "action.task_benchmark" .GetRepoLink .Content .RefName | Str2html}} {{$.i18n.Tr "action.task_benchmark" .GetRepoLink .Content .RefName | Str2html}}
{{else if eq .GetOpType 30}} {{else if eq .GetOpType 30}}
{{$.i18n.Tr "action.task_createmodel" .GetRepoLink .RefName .RefName | Str2html}} {{$.i18n.Tr "action.task_createmodel" .GetRepoLink .RefName .RefName | Str2html}}
{{else if eq .GetOpType 31}}
{{$.i18n.Tr "action.task_gputrainjob" .GetRepoLink .Content .RefName | Str2html}}
{{end}} {{end}}
</p> </p>
{{if or (eq .GetOpType 5) (eq .GetOpType 18)}} {{if or (eq .GetOpType 5) (eq .GetOpType 18)}}
@@ -129,6 +131,8 @@
<span class="text grey"><i class="ri-vip-crown-line icon big"></i></span> <span class="text grey"><i class="ri-vip-crown-line icon big"></i></span>
{{else if eq .GetOpType 30}} {{else if eq .GetOpType 30}}
<span class="text grey"><i class="ri-picture-in-picture-exit-line icon big"></i></span> <span class="text grey"><i class="ri-picture-in-picture-exit-line icon big"></i></span>
{{else if eq .GetOpType 31}}
<span class="text grey"><i class="ri-character-recognition-line icon big"></i></span>
{{else}} {{else}}
<span class="text grey">{{svg (printf "octicon-%s" (ActionIcon .GetOpType)) 32}}</span> <span class="text grey">{{svg (printf "octicon-%s" (ActionIcon .GetOpType)) 32}}</span>
{{end}} {{end}}


+ 7
- 7
web_src/js/components/ProAnalysis.vue View File

@@ -150,21 +150,21 @@
align="center"> align="center">
</el-table-column> </el-table-column>
<el-table-column <el-table-column
prop="isMirror"
prop="isFork"
label="派生" label="派生"
align="center"> align="center">
<template slot-scope="scope"> <template slot-scope="scope">
{{scope.row.isMirror|changeType}}
</template>
</el-table-column>
{{scope.row.isFork|changeType}}
</template>
</el-table-column>
<el-table-column <el-table-column
prop="isFork"
prop="isMirror"
label="镜像" label="镜像"
align="center"> align="center">
<template slot-scope="scope"> <template slot-scope="scope">
{{scope.row.isFork|changeType}}
{{scope.row.isMirror|changeType}}
</template> </template>
</el-table-column>
</el-table-column>
<el-table-column <el-table-column
prop="createUnix" prop="createUnix"
label="项目创建时间" label="项目创建时间"


+ 43
- 1
web_src/js/components/UserAnalysis.vue View File

@@ -133,7 +133,43 @@
<template slot-scope="scope"> <template slot-scope="scope">
{{scope.row.RegistDate | transformTimestamp}} {{scope.row.RegistDate | transformTimestamp}}
</template> </template>
</el-table-column>
<el-table-column
prop="CloudBrainTaskNum"
label="云脑任务数"
width="120px"
align="center">
</el-table-column> </el-table-column>
<el-table-column
prop="CloudBrainRunTime"
label="云脑运行时间(小时)"
width="120px"
align="center">
<template slot-scope="scope">
{{scope.row.CloudBrainRunTime | roundingToHour}}
</template>
</el-table-column>
<el-table-column
prop="CommitDatasetNum"
label="上传(提交)数据集文件数"
width="120px"
align="center">
</el-table-column>
<el-table-column
prop="CommitModelCount"
label="提交模型数"
width="120px"
align="center">
</el-table-column>
<el-table-column
prop="UserIndex"
label="用户指数"
width="120px"
align="center">
<template slot-scope="scope">
{{scope.row.UserIndex | rounding}}
</template>
</el-table-column>
<el-table-column <el-table-column
prop="DataDate" prop="DataDate"
label="系统统计时间" label="系统统计时间"
@@ -178,7 +214,7 @@
value_time: '', value_time: '',
search:'', search:'',
data:'', data:'',
columns: [{title: 'ID',key: 'ID'},{title: '用户名',key: 'Name'},{title: 'PR数',key: 'CodeMergeCount'},{title: 'commit数',key:'CommitCount'},{title: '提出任务数',key: 'IssueCount'},{title: '评论数',key: 'CommentCount'},{title: '关注项目数',key: 'FocusRepoCount'},{title: '点赞项目数',key: 'StarRepoCount'},{title: '登录次数',key: 'LoginCount'},{title:'关注者数',key:'WatchedCount'},{title:'commit代码行数',key:'CommitCodeSize'},{title:'已解决任务数',key:'SolveIssueCount'},{title:'百科页面贡献次数',key:'EncyclopediasCount'},{title:'创建项目',key:'CreateRepoCount'},{title:'用户注册时间',key:'RegistDate'},{title:'系统统计时间',key:'CountDate'}],
columns: [{title: 'ID',key: 'ID'},{title: '用户名',key: 'Name'},{title: 'PR数',key: 'CodeMergeCount'},{title: 'commit数',key:'CommitCount'},{title: '提出任务数',key: 'IssueCount'},{title: '评论数',key: 'CommentCount'},{title: '关注项目数',key: 'FocusRepoCount'},{title: '点赞项目数',key: 'StarRepoCount'},{title: '登录次数',key: 'LoginCount'},{title:'关注者数',key:'WatchedCount'},{title:'commit代码行数',key:'CommitCodeSize'},{title:'已解决任务数',key:'SolveIssueCount'},{title:'百科页面贡献次数',key:'EncyclopediasCount'},{title:'创建项目',key:'CreateRepoCount'},{title:'用户注册时间',key:'RegistDate'},{title:'云脑任务数',key:'CloudBrainTaskNum'},{title:'云脑运行时间(小时)',key:'CloudBrainRunTime'},{title:'上传(提交)数据集文件数',key:'CommitDatasetNum'},{title:'提交模型数',key:'CommitModelCount'},{title:'用户指数',key:'UserIndex'},{title:'系统统计时间',key:'CountDate'}],
blob:'', blob:'',
fileName:'', fileName:'',
dynamic:7, dynamic:7,
@@ -351,6 +387,12 @@
}, },
filters:{ filters:{
rounding (value) {
return Number(value).toFixed(2)
},
roundingToHour (value) {
return (Number(value)/3600).toFixed(2)
},
transformTimestamp(timestamp){ transformTimestamp(timestamp){
let a = new Date(timestamp*1000); let a = new Date(timestamp*1000);
const date = new Date(a); const date = new Date(a);


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

@@ -628,6 +628,32 @@ display: block;
.a_margin{ .a_margin{
margin: 0px !important; margin: 0px !important;
} }

/*pages*/
.ui.borderless.pagination {border:none}
.ui.pagination.menu .item {
min-width: 32px;
text-align: center;
height: 32px;
border-radius: .28571429rem;
margin: 0 5px;
background-color: #F2F2F2;
}
.ui.pagination.menu>.item:first-child, .ui.pagination.menu .item:last-child {
background-color: #FFF !important;
}
.ui.ui.menu .item.disabled{
background-color: #F2F2F2;
}
.ui.pagination.menu .active.item {
background-color: #3291F8;
color: #FFF;
}
.ui.pagination.menu .item>.input {
margin: 0em .5em;
width: 3em;
height: 32px;
}
@media only screen and (max-width: 767px) { @media only screen and (max-width: 767px) {
.following.bar #navbar .brand{ .following.bar #navbar .brand{
padding-top: 6px; padding-top: 6px;
@@ -783,4 +809,170 @@ display: block;
border: none !important; border: none !important;
color: #0366d6 !important; color: #0366d6 !important;
box-shadow: -15px 0px 10px #fff; box-shadow: -15px 0px 10px #fff;
}

.content_top10{
padding:10px;
padding-top:0px;
}
.re_con{
color: rgba(136, 136, 136, 100);
font-size: 14px;
text-align: center;
font-family: SourceHanSansSC-light;
}
.title_re{
margin-top: 50px !important;
}
.card_list {
width: calc(33.33333333333333% - 2em);
margin-left: 1em;
margin-right: 1em
}
.list_title{
height: 52px;
text-align: center
}
.star_title{
background-color: #3291F8;
}
.memb_title{
background-color: #706FE3;
}
.act_title{
background-color: #13C28D;
}
.p_text{
line-height: 50px;
text-align:left;
padding-left:15px;
font-size:18px;
color:#FFFFFF;
}
.orgs {
display: flex;
flex-flow: row wrap;
padding: 0;
margin-top:20px
}
.orgs li {
display: flex;
border-bottom: 0!important;
padding: 3px!important;
}
.p_score{
line-height: 28px;
width: 100%;
/* padding-right: 20px; */
text-align: right;
}
.org_line_hight{
line-height: 28px;
}
.org_icon{
margin-top: 10px;
margin-right: 10px;
padding-left: 15px;
}
.org_icon_num{
margin-left: 2px;
margin-right: 13px;
}
.org_icon_color{
color: #FA8C16;
}
.li_name{
list-style:none;
width: 55%;
}
.li_avatar{
list-style: none;
width: 10%;
}
.li_score{
list-style:none;
margin-left: 2px;
}
/**seach**/
/**搜索导航条适配窄屏**/
.seachnav{
overflow-x: auto;
overflow-y: hidden;
scrollbar-width: none; /* firefox */
-ms-overflow-style: none; /* IE 10+ */
}
.seachnav::-webkit-scrollbar {
display: none; /* Chrome Safari */
}
.ui.green.button, .ui.green.buttons .button{
background-color: #5BB973;
}
.seach .repos--seach{
padding-bottom: 0;
border-bottom: none;
}
.seach .ui.secondary.pointing.menu{
border-bottom: none;
}
.seach .ui.secondary.pointing.menu .item > i{
margin-right: 5px;
}
.seach .ui.secondary.pointing.menu .active.item{
border-bottom-width: 2px;
margin: 0 0 -1px;
}
.seach .ui.menu .active.item>.label {
background: #1684FC;
color: #FFF;
}
.seach .ui.menu .item>.label:not(.active.item>.label) {
background: #e8e8e8;
color: rgba(0,0,0,.6);
}
.highlight{
color: red;
}
.ui.list .list>.item>img.image+.content, .ui.list>.item>img.image+.content {
width: calc(100% - 4.0em);
margin-left: 0;
}
.seach .ui.list .list>.item .header, .seach .ui.list>.item .header{
margin-bottom: 0.5em;
font-size: 1.4rem !important;
font-weight: normal;
}
.seach .time, .seach .time a{
font-size: 12px;
color: grey;
}
.seach .list .item.members .ui.avatar.image {
width: 3.2em;
height: 3.2em;
}
.ui.list .list>.item.members>img.image+.content, .ui.list>.item.members>img.image+.content {
width: calc(100% - 4.0em);
margin-left: 0;
}

.searchlabel{
color: rgba(16, 16, 16, 100);
font-size: 24px;
text-align: left;
font-family: SourceHanSansSC-medium;
}

.hiddenSearch{
margin: auto;
display: none;
}

#tipmsg {
display: none;
z-index: 9999;
width:150;
height: 80;
} }

Loading…
Cancel
Save