Browse Source

merge

tags/v1.22.11.3^2
ychao_1983 2 years ago
parent
commit
b763d9e9d2
75 changed files with 5351 additions and 1411 deletions
  1. +10
    -10
      README.md
  2. +32
    -0
      models/ai_model_manage.go
  3. +2
    -2
      models/attachment.go
  4. +58
    -6
      models/cloudbrain.go
  5. +43
    -29
      models/cloudbrain_static.go
  6. +75
    -0
      models/file_chunk.go
  7. +2
    -0
      models/models.go
  8. +3
    -3
      models/resource_queue.go
  9. +2
    -2
      models/resource_scene.go
  10. +21
    -8
      models/resource_specification.go
  11. +377
    -227
      models/user_business_analysis.go
  12. +200
    -0
      models/user_business_struct.go
  13. +26
    -0
      modules/grampus/resty.go
  14. +27
    -13
      modules/setting/setting.go
  15. +2
    -2
      modules/storage/minio.go
  16. +26
    -10
      modules/storage/minio_ext.go
  17. +24
    -25
      modules/storage/obs.go
  18. +4
    -2
      options/locale/locale_en-US.ini
  19. +4
    -2
      options/locale/locale_zh-CN.ini
  20. +6
    -2
      routers/admin/cloudbrains.go
  21. +21
    -0
      routers/admin/resources.go
  22. +5
    -1
      routers/api/v1/api.go
  23. +23
    -3
      routers/api/v1/repo/cloudbrain.go
  24. +188
    -89
      routers/api/v1/repo/cloudbrain_dashboard.go
  25. +13
    -11
      routers/api/v1/repo/modelarts.go
  26. +9
    -0
      routers/api/v1/repo/modelmanage.go
  27. +4
    -1
      routers/private/internal.go
  28. +6
    -0
      routers/repo/ai_model_convert.go
  29. +291
    -32
      routers/repo/ai_model_manage.go
  30. +18
    -17
      routers/repo/attachment.go
  31. +323
    -0
      routers/repo/attachment_model.go
  32. +157
    -65
      routers/repo/cloudbrain_statistic.go
  33. +70
    -12
      routers/repo/grampus.go
  34. +20
    -0
      routers/routes/routes.go
  35. +4
    -0
      routers/user/home.go
  36. +1
    -1
      services/cloudbrain/cloudbrainTask/sync_status.go
  37. +1
    -1
      services/cloudbrain/resource/resource_queue.go
  38. +41
    -1
      services/cloudbrain/resource/resource_specification.go
  39. +40
    -0
      services/cloudbrain/util.go
  40. +6
    -6
      templates/admin/cloudbrain/list.tmpl
  41. +4
    -6
      templates/admin/cloudbrain/search.tmpl
  42. +4
    -6
      templates/admin/cloudbrain/search_dashboard.tmpl
  43. +21
    -2
      templates/base/footer_content.tmpl
  44. +21
    -1
      templates/base/footer_content_fluid.tmpl
  45. +0
    -71
      templates/repo/cloudbrain/inference/show.tmpl
  46. +12
    -144
      templates/repo/cloudbrain/trainjob/show.tmpl
  47. +11
    -5
      templates/repo/grampus/trainjob/show.tmpl
  48. +2
    -3
      templates/repo/modelarts/trainjob/show.tmpl
  49. +10
    -0
      templates/repo/modelmanage/create_local_1.tmpl
  50. +11
    -0
      templates/repo/modelmanage/create_local_2.tmpl
  51. +581
    -0
      templates/repo/modelmanage/create_online.tmpl
  52. +25
    -3
      templates/repo/modelmanage/index.tmpl
  53. +5
    -528
      templates/repo/modelmanage/showinfo.tmpl
  54. +2
    -1
      templates/repo/modelsafety/show.tmpl
  55. +7
    -7
      templates/user/dashboard/cloudbrains.tmpl
  56. +52
    -19
      web_src/js/components/Model.vue
  57. +1
    -1
      web_src/js/components/basic/editDialog.vue
  58. +1
    -1
      web_src/js/features/cloudrbanin.js
  59. +6
    -0
      web_src/js/features/i18nVue.js
  60. +11
    -10
      web_src/js/index.js
  61. +106
    -0
      web_src/vuepages/apis/modules/modelmanage.js
  62. +13
    -0
      web_src/vuepages/apis/modules/resources.js
  63. +3
    -0
      web_src/vuepages/const/index.js
  64. +64
    -3
      web_src/vuepages/langs/config/en-US.js
  65. +63
    -0
      web_src/vuepages/langs/config/zh-CN.js
  66. +3
    -5
      web_src/vuepages/pages/model/tuomin/index.vue
  67. +706
    -0
      web_src/vuepages/pages/modelmanage/common/modelmanage-common-detail.vue
  68. +17
    -0
      web_src/vuepages/pages/modelmanage/common/vp-modelmanage-common-detail.js
  69. +470
    -0
      web_src/vuepages/pages/modelmanage/local/modelmanage-local-create-1.vue
  70. +851
    -0
      web_src/vuepages/pages/modelmanage/local/modelmanage-local-create-2.vue
  71. +17
    -0
      web_src/vuepages/pages/modelmanage/local/vp-modelmanage-local-create-1.js
  72. +17
    -0
      web_src/vuepages/pages/modelmanage/local/vp-modelmanage-local-create-2.js
  73. +9
    -7
      web_src/vuepages/pages/resources/components/SceneDialog.vue
  74. +5
    -4
      web_src/vuepages/pages/resources/scene/index.vue
  75. +35
    -1
      web_src/vuepages/utils/index.js

+ 10
- 10
README.md View File

@@ -2,7 +2,7 @@

<h1><img src="public/img/favicon.png" alt="logo" width="30" height="30">AiForge - 启智AI开发协作平台</h1>

[![release](https://img.shields.io/badge/release-1.21.11.1-blue)](https://git.openi.org.cn/OpenI/aiforge/releases/latest)
[![release](https://img.shields.io/badge/release-1.21.11.1-blue)](https://openi.pcl.ac.cn/OpenI/aiforge/releases/latest)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)


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

启智AI开发协作平台是一个在线Web应用,旨在为人工智能算法、模型开发提供在线协同工作环境,它提供了<b>代码托管、数据集管理与共享、免费云端算力资源支持(GPU/NPU)、共享镜像</b>等功能。

[启智AI开发协作平台](https://git.openi.org.cn) 是使用本项目构建的在线服务,您可以直接点击链接访问试用。
[启智AI开发协作平台](https://openi.pcl.ac.cn) 是使用本项目构建的在线服务,您可以直接点击链接访问试用。

本项目是基于[Gitea](https://github.com/go-gitea/gitea)发展而来的,我们对其进行了Fork并基于此扩展了人工智能开发中需要的功能,如数据集管理和模型训练等。对于和代码托管相关的功能,您可以参考[Gitea的文档](https://docs.gitea.io/zh-cn/)。

@@ -20,7 +20,7 @@
后端服务涵盖了AI模型开发流水线,包括代码协同开发、数据管理、模型调试、训练、推理和部署等(*目前尚未支持模型部署*)。在不同的开发阶段,我们还将提供丰富的开发工具供用户使用,如数据标注、数据筛选、模型转换、模型压缩、代码检测等。我们也欢迎社区提供更多丰富的工具接入,提高利用平台进行开发的效率。
![系统架构图](assets/架构图.png)
## 在线服务使用
本项目的在线服务平台的详细使用帮助文档,可参阅本项目[百科](https://git.openi.org.cn/OpenI/aiforge/wiki)内容。
本项目的在线服务平台的详细使用帮助文档,可参阅本项目[百科](https://openi.pcl.ac.cn/OpenI/aiforge/wiki)内容。
- 如何创建账号
- 如何创建组织及管理成员权限
- 如何创建项目仓库
@@ -39,22 +39,22 @@
[从源代码安装说明](https://docs.gitea.io/zh-cn/install-from-source/)

## 授权许可
本项目采用 MIT 开源授权许可证,完整的授权说明已放置在 [LICENSE](https://git.openi.org.cn/OpenI/aiforge/src/branch/develop/LICENSE) 文件中。
本项目采用 MIT 开源授权许可证,完整的授权说明已放置在 [LICENSE](https://openi.pcl.ac.cn/OpenI/aiforge/src/branch/develop/LICENSE) 文件中。


## 需要帮助?
如果您在使用或者开发过程中遇到问题,可以在以下渠道咨询:
- 点击[这里](https://git.openi.org.cn/OpenI/aiforge/issues)在线提交问题(点击页面右上角绿色按钮**创建任务**)
- 点击[这里](https://openi.pcl.ac.cn/OpenI/aiforge/issues)在线提交问题(点击页面右上角绿色按钮**创建任务**)
- 加入微信群实时交流,获得进一步的支持
<img src="https://git.openi.org.cn/OpenI/aiforge/wiki/raw/img/wechatgroup.jpg" width=200px />
<img src="https://openi.pcl.ac.cn/OpenI/aiforge/wiki/raw/img/wechatgroup.jpg" width=200px />

## 启智社区小白训练营:
- 结合案例给大家详细讲解如何使用社区平台,帮助无技术背景的小白成长为启智社区达人 (https://git.openi.org.cn/zeizei/OpenI_Learning)
- 结合案例给大家详细讲解如何使用社区平台,帮助无技术背景的小白成长为启智社区达人 (https://openi.pcl.ac.cn/zeizei/OpenI_Learning)

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

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

+ 32
- 0
models/ai_model_manage.go View File

@@ -14,6 +14,7 @@ import (
type AiModelManage struct {
ID string `xorm:"pk" json:"id"`
Name string `xorm:"INDEX NOT NULL" json:"name"`
ModelType int `xorm:"NULL" json:"modelType"`
Version string `xorm:"NOT NULL" json:"version"`
VersionCount int `xorm:"NOT NULL DEFAULT 0" json:"versionCount"`
New int `xorm:"NOT NULL" json:"new"`
@@ -287,6 +288,37 @@ func ModifyModelDescription(id string, description string) error {
return nil
}

func ModifyLocalModel(id string, name, label, description string, engine int) error {
var sess *xorm.Session
sess = x.ID(id)
defer sess.Close()
re, err := sess.Cols("name", "label", "description", "engine").Update(&AiModelManage{
Description: description,
Name: name,
Label: label,
Engine: int64(engine),
})
if err != nil {
return err
}
log.Info("success to update description from db.re=" + fmt.Sprint((re)))
return nil
}

func ModifyModelSize(id string, size int64) error {
var sess *xorm.Session
sess = x.ID(id)
defer sess.Close()
re, err := sess.Cols("size").Update(&AiModelManage{
Size: size,
})
if err != nil {
return err
}
log.Info("success to update size from db.re=" + fmt.Sprint((re)))
return nil
}

func ModifyModelStatus(id string, modelSize int64, status int, modelPath string, statusDesc string) error {
var sess *xorm.Session
sess = x.ID(id)


+ 2
- 2
models/attachment.go View File

@@ -134,7 +134,8 @@ func (a *Attachment) S3DownloadURL() string {
if a.Type == TypeCloudBrainOne {
url, _ = storage.Attachments.PresignedGetURL(setting.Attachment.Minio.BasePath+AttachmentRelativePath(a.UUID), a.Name)
} else if a.Type == TypeCloudBrainTwo {
url, _ = storage.ObsGetPreSignedUrl(a.UUID, a.Name)
objectName := strings.TrimPrefix(path.Join(setting.BasePath, path.Join(a.UUID[0:1], a.UUID[1:2], a.UUID, a.Name)), "/")
url, _ = storage.ObsGetPreSignedUrl(objectName, a.Name)
}

return url
@@ -550,7 +551,6 @@ func AttachmentsByDatasetOption(datasets []int64, opts *SearchDatasetOptions) ([
)
}


attachments := make([]*Attachment, 0)
if err := sess.Table(&Attachment{}).Where(cond).Desc("id").
Find(&attachments); err != nil {


+ 58
- 6
models/cloudbrain.go View File

@@ -291,12 +291,30 @@ func (task *Cloudbrain) IsRunning() bool {
status == string(JobRunning) || status == GrampusStatusRunning
}

func (task *Cloudbrain) IsUserHasRight(user *User) bool {
if user == nil {
return false
}
return user.IsAdmin || user.ID == task.UserID
}

func ConvertDurationToStr(duration int64) string {
if duration <= 0 {
return DURATION_STR_ZERO
}
return util.AddZero(duration/3600) + ":" + util.AddZero(duration%3600/60) + ":" + util.AddZero(duration%60)
}
func ConvertStrToDuration(trainJobDuration string) int64 {
trainJobDurationList := strings.Split(trainJobDuration, ":")
if len(trainJobDurationList) == 3 {
i, _ := strconv.ParseInt(trainJobDurationList[0], 10, 64)
j, _ := strconv.ParseInt(trainJobDurationList[1], 10, 64)
k, _ := strconv.ParseInt(trainJobDurationList[2], 10, 64)
return i*3600 + j*60 + k
} else {
return 0
}
}

func IsTrainJobTerminal(status string) bool {
return status == string(ModelArtsTrainJobCompleted) || status == string(ModelArtsTrainJobFailed) || status == string(ModelArtsTrainJobKilled) || status == GrampusStatusFailed || status == GrampusStatusStopped || status == GrampusStatusSucceeded
@@ -1589,9 +1607,23 @@ func Cloudbrains(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, error) {
}
}
if (opts.AiCenter) != "" {
cond = cond.And(
builder.Like{"cloudbrain.ai_center", opts.AiCenter},
)
if opts.AiCenter == AICenterOfCloudBrainOne {
cond = cond.And(
builder.Eq{"cloudbrain.type": TypeCloudBrainOne},
)
} else if opts.AiCenter == AICenterOfCloudBrainTwo {
cond = cond.And(
builder.Eq{"cloudbrain.type": TypeCloudBrainTwo},
)
} else if opts.AiCenter == AICenterOfChengdu {
cond = cond.And(
builder.Eq{"cloudbrain.type": TypeCDCenter},
)
} else {
cond = cond.And(
builder.Like{"cloudbrain.ai_center", opts.AiCenter},
)
}
}
if (opts.Cluster) != "" {
if opts.Cluster == "resource_cluster_openi" {
@@ -1968,7 +2000,7 @@ func UpdateTrainJobVersion(job *Cloudbrain) error {
func updateJobTrainVersion(e Engine, job *Cloudbrain) error {
var sess *xorm.Session
sess = e.Where("job_id = ? AND version_name=?", job.JobID, job.VersionName)
_, err := sess.Cols("status", "train_job_duration", "duration", "start_time", "end_time", "created_unix").Update(job)
_, err := sess.Cols("status", "train_job_duration", "duration", "start_time", "end_time", "created_unix", "ai_center").Update(job)
return err
}

@@ -2030,10 +2062,17 @@ func GetStoppedJobWithNoStartTimeEndTime() ([]*Cloudbrain, error) {
cloudbrains := make([]*Cloudbrain, 0)
return cloudbrains, x.SQL("select * from cloudbrain where status in (?,?,?,?,?,?,?) and (start_time is null or end_time is null) limit 100", ModelArtsTrainJobCompleted, ModelArtsTrainJobFailed, ModelArtsTrainJobKilled, ModelArtsStopped, JobStopped, JobFailed, JobSucceeded).Find(&cloudbrains)
}
func GetC2NetWithAiCenterWrongJob() ([]*Cloudbrain, error) {
cloudbrains := make([]*Cloudbrain, 0)
return cloudbrains, x.
In("status", ModelArtsTrainJobCompleted, ModelArtsTrainJobFailed, ModelArtsTrainJobKilled, ModelArtsStopped, JobStopped, JobFailed, JobSucceeded).
Where("type = ?", TypeC2Net).
Find(&cloudbrains)
}

func GetModelSafetyTestTask() ([]*Cloudbrain, error) {
cloudbrains := make([]*Cloudbrain, 0)
sess := x.Where("job_type = ?", string(JobTypeModelSafety))
sess := x.Where("job_type=?", string(JobTypeModelSafety))
err := sess.Find(&cloudbrains)
return cloudbrains, err
}
@@ -2285,10 +2324,23 @@ func CloudbrainAllStatic(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, er
}
// sess.OrderBy("cloudbrain.created_unix DESC")
cloudbrains := make([]*CloudbrainInfo, 0, setting.UI.IssuePagingNum)
if err := sess.Cols("status", "type", "job_type", "train_job_duration", "duration", "compute_resource", "created_unix", "start_time", "end_time", "work_server_number").Table(&Cloudbrain{}).Unscoped().Where(cond).
if err := sess.Table(&Cloudbrain{}).Unscoped().Where(cond).
Find(&cloudbrains); err != nil {
return nil, 0, fmt.Errorf("Find: %v", err)
}
if opts.NeedRepoInfo {
var ids []int64
for _, task := range cloudbrains {
ids = append(ids, task.RepoID)
}
repositoryMap, err := GetRepositoriesMapByIDs(ids)
if err == nil {
for _, task := range cloudbrains {
task.Repo = repositoryMap[task.RepoID]
}
}

}
return cloudbrains, count, nil
}



+ 43
- 29
models/cloudbrain_static.go View File

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

import (
"fmt"
"strconv"
"time"

@@ -42,14 +41,14 @@ type TaskDetail struct {
type CloudbrainDurationStatistic struct {
ID int64 `xorm:"pk autoincr"`
Cluster string
AiCenterCode string
AiCenterCode string `xorm:"INDEX"`
AiCenterName string
ComputeResource string
AccCardType string
AccCardType string `xorm:"INDEX"`

DateTime string
DayTime string
HourTime int
DateTime timeutil.TimeStamp `xorm:"INDEX"`
DayTime string `xorm:"INDEX"`
HourTime int `xorm:"INDEX"`
CardsUseDuration int
CardsTotalDuration int
CardsTotalNum int
@@ -275,11 +274,15 @@ func GetCloudbrainByTime(beginTime int64, endTime int64) ([]*CloudbrainInfo, err
sess := x.NewSession()
defer sess.Close()
var cond = builder.NewCond()
cond = cond.And(
builder.And(builder.Gte{"cloudbrain.end_time": beginTime}, builder.Lte{"cloudbrain.end_time": endTime}),
sess.Exec("if ")
cond = cond.Or(
builder.And(builder.Gte{"cloudbrain.end_time": beginTime}, builder.Lte{"cloudbrain.start_time": beginTime}, builder.Gt{"cloudbrain.start_time": 0}),
)
cond = cond.Or(
builder.Eq{"cloudbrain.status": string(JobRunning)},
builder.And(builder.Gte{"cloudbrain.start_time": beginTime}, builder.Lte{"cloudbrain.start_time": endTime}, builder.Gt{"cloudbrain.start_time": 0}),
)
cond = cond.Or(
builder.And(builder.Eq{"cloudbrain.status": string(JobRunning)}),
)
sess.OrderBy("cloudbrain.created_unix ASC")
cloudbrains := make([]*CloudbrainInfo, 0, 10)
@@ -309,30 +312,20 @@ func InsertCloudbrainDurationStatistic(cloudbrainDurationStatistic *CloudbrainDu
return xStatistic.Insert(cloudbrainDurationStatistic)
}

func DeleteCloudbrainDurationStatisticHour(date string, hour int, aiCenterCode string, accCardType string) error {
sess := xStatistic.NewSession()
defer sess.Close()
if err := sess.Begin(); err != nil {
return fmt.Errorf("Begin: %v", err)
}

if _, err := sess.Where("day_time = ? AND hour_time = ? AND ai_center_code = ? AND acc_card_type = ?", date, hour, aiCenterCode, accCardType).Delete(&CloudbrainDurationStatistic{}); err != nil {
return fmt.Errorf("Delete: %v", err)
func getDurationStatistic(cb *CloudbrainDurationStatistic) (*CloudbrainDurationStatistic, error) {
has, err := x.Get(cb)
if err != nil {
return nil, err
} else if !has {
return nil, ErrJobNotExist{}
}

if err := sess.Commit(); err != nil {
sess.Close()
return fmt.Errorf("Commit: %v", err)
}

sess.Close()
return nil
return cb, nil
}

func GetCanUseCardInfo() ([]*ResourceQueue, error) {
sess := x.NewSession()
defer sess.Close()
sess.OrderBy("resource_queue.id ASC")
sess.OrderBy("resource_queue.cluster DESC, resource_queue.ai_center_code ASC")
ResourceQueues := make([]*ResourceQueue, 0, 10)
if err := sess.Table(&ResourceQueue{}).Find(&ResourceQueues); err != nil {
log.Info("find error.")
@@ -346,7 +339,7 @@ func GetCardDurationStatistics(opts *DurationStatisticOptions) ([]*CloudbrainDur
var cond = builder.NewCond()
if opts.BeginTime.Unix() > 0 && opts.EndTime.Unix() > 0 {
cond = cond.And(
builder.And(builder.Gte{"cloudbrain_duration_statistic.created_unix": opts.BeginTime.Unix()}, builder.Lte{"cloudbrain_duration_statistic.created_unix": opts.EndTime.Unix()}),
builder.And(builder.Gte{"cloudbrain_duration_statistic.date_time": opts.BeginTime.Unix()}, builder.Lt{"cloudbrain_duration_statistic.date_time": opts.EndTime.Unix()}),
)
}
if opts.AiCenterCode != "" {
@@ -365,10 +358,31 @@ func GetCardDurationStatistics(opts *DurationStatisticOptions) ([]*CloudbrainDur
func GetDurationRecordBeginTime() ([]*CloudbrainDurationStatistic, error) {
sess := xStatistic.NewSession()
defer sess.Close()
sess.OrderBy("cloudbrain_duration_statistic.id ASC limit 1")
sess.OrderBy("cloudbrain_duration_statistic.date_time ASC limit 1")
CloudbrainDurationStatistics := make([]*CloudbrainDurationStatistic, 0)
if err := sess.Table(&CloudbrainDurationStatistic{}).Find(&CloudbrainDurationStatistics); err != nil {
log.Info("find error.")
}
return CloudbrainDurationStatistics, nil
}

func GetDurationRecordUpdateTime() ([]*CloudbrainDurationStatistic, error) {
sess := xStatistic.NewSession()
defer sess.Close()
sess.OrderBy("cloudbrain_duration_statistic.date_time DESC limit 1")
CloudbrainDurationStatistics := make([]*CloudbrainDurationStatistic, 0)
if err := sess.Table(&CloudbrainDurationStatistic{}).Find(&CloudbrainDurationStatistics); err != nil {
log.Info("find error.")
}
return CloudbrainDurationStatistics, nil
}

func DeleteCloudbrainDurationStatistic(beginTime timeutil.TimeStamp, endTime timeutil.TimeStamp) error {
sess := xStatistic.NewSession()
defer sess.Close()
if _, err := sess.Exec("DELETE FROM cloudbrain_duration_statistic WHERE cloudbrain_duration_statistic.date_time BETWEEN ? AND ?", beginTime, endTime); err != nil {
log.Info("DELETE cloudbrain_duration_statistic data error.")
return err
}
return nil
}

+ 75
- 0
models/file_chunk.go View File

@@ -28,6 +28,23 @@ type FileChunk struct {
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
}

type ModelFileChunk struct {
ID int64 `xorm:"pk autoincr"`
UUID string `xorm:"INDEX"`
Md5 string `xorm:"INDEX"`
ModelUUID string `xorm:"INDEX"`
ObjectName string `xorm:"DEFAULT ''"`
IsUploaded int `xorm:"DEFAULT 0"` // not uploaded: 0, uploaded: 1
UploadID string `xorm:"UNIQUE"` //minio upload id
TotalChunks int
Size int64
UserID int64 `xorm:"INDEX"`
Type int `xorm:"INDEX DEFAULT 0"`
CompletedParts []string `xorm:"DEFAULT ''"` // chunkNumber+etag eg: ,1-asqwewqe21312312.2-123hjkas
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
}

// GetFileChunkByMD5 returns fileChunk by given id
func GetFileChunkByMD5(md5 string) (*FileChunk, error) {
return getFileChunkByMD5(x, md5)
@@ -49,6 +66,21 @@ func GetFileChunkByMD5AndUser(md5 string, userID int64, typeCloudBrain int) (*Fi
return getFileChunkByMD5AndUser(x, md5, userID, typeCloudBrain)
}

func GetModelFileChunkByMD5AndUser(md5 string, userID int64, typeCloudBrain int, uuid string) (*ModelFileChunk, error) {
return getModelFileChunkByMD5AndUser(x, md5, userID, typeCloudBrain, uuid)
}

func getModelFileChunkByMD5AndUser(e Engine, md5 string, userID int64, typeCloudBrain int, uuid string) (*ModelFileChunk, error) {
fileChunk := new(ModelFileChunk)

if has, err := e.Where("md5 = ? and user_id = ? and type = ? and model_uuid= ?", md5, userID, typeCloudBrain, uuid).Get(fileChunk); err != nil {
return nil, err
} else if !has {
return nil, ErrFileChunkNotExist{md5, ""}
}
return fileChunk, nil
}

func getFileChunkByMD5AndUser(e Engine, md5 string, userID int64, typeCloudBrain int) (*FileChunk, error) {
fileChunk := new(FileChunk)

@@ -76,6 +108,21 @@ func getFileChunkByUUID(e Engine, uuid string) (*FileChunk, error) {
return fileChunk, nil
}

func GetModelFileChunkByUUID(uuid string) (*ModelFileChunk, error) {
return getModelFileChunkByUUID(x, uuid)
}

func getModelFileChunkByUUID(e Engine, uuid string) (*ModelFileChunk, error) {
fileChunk := new(ModelFileChunk)

if has, err := e.Where("uuid = ?", uuid).Get(fileChunk); err != nil {
return nil, err
} else if !has {
return nil, ErrFileChunkNotExist{"", uuid}
}
return fileChunk, nil
}

// InsertFileChunk insert a record into file_chunk.
func InsertFileChunk(fileChunk *FileChunk) (_ *FileChunk, err error) {
if _, err := x.Insert(fileChunk); err != nil {
@@ -85,6 +132,14 @@ func InsertFileChunk(fileChunk *FileChunk) (_ *FileChunk, err error) {
return fileChunk, nil
}

// InsertFileChunk insert a record into file_chunk.
func InsertModelFileChunk(fileChunk *ModelFileChunk) (_ *ModelFileChunk, err error) {
if _, err := x.Insert(fileChunk); err != nil {
return nil, err
}
return fileChunk, nil
}

func DeleteFileChunkById(uuid string) (*FileChunk, error) {
return deleteFileChunkById(x, uuid)
}
@@ -106,6 +161,17 @@ func deleteFileChunkById(e Engine, uuid string) (*FileChunk, error) {
}
}

func UpdateModelFileChunk(fileChunk *ModelFileChunk) error {
return updateModelFileChunk(x, fileChunk)
}

func updateModelFileChunk(e Engine, fileChunk *ModelFileChunk) error {
var sess *xorm.Session
sess = e.Where("uuid = ?", fileChunk.UUID)
_, err := sess.Cols("is_uploaded").Update(fileChunk)
return err
}

// UpdateFileChunk updates the given file_chunk in database
func UpdateFileChunk(fileChunk *FileChunk) error {
return updateFileChunk(x, fileChunk)
@@ -127,3 +193,12 @@ func deleteFileChunk(e Engine, fileChunk *FileChunk) error {
_, err := e.ID(fileChunk.ID).Delete(fileChunk)
return err
}

func DeleteModelFileChunk(fileChunk *ModelFileChunk) error {
return deleteModelFileChunk(x, fileChunk)
}

func deleteModelFileChunk(e Engine, fileChunk *ModelFileChunk) error {
_, err := e.ID(fileChunk.ID).Delete(fileChunk)
return err
}

+ 2
- 0
models/models.go View File

@@ -136,6 +136,7 @@ func init() {
new(ImageTopic),
new(ImageTopicRelation),
new(FileChunk),
new(ModelFileChunk),
new(BlockChain),
new(RecommendOrg),
new(AiModelManage),
@@ -185,6 +186,7 @@ func init() {
new(UserAnalysisPara),
new(Invitation),
new(CloudbrainDurationStatistic),
new(UserSummaryCurrentYear),
)

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


+ 3
- 3
models/resource_queue.go View File

@@ -143,6 +143,9 @@ func InsertResourceQueue(queue ResourceQueue) (int64, error) {
func UpdateResourceQueueById(queueId int64, queue ResourceQueue) (int64, error) {
return x.ID(queueId).Update(&queue)
}
func UpdateResourceCardsTotalNum(queueId int64, queue ResourceQueue) (int64, error) {
return x.ID(queueId).Cols("cards_total_num", "remark").Update(&queue)
}

func SearchResourceQueue(opts SearchResourceQueueOptions) (int64, []ResourceQueue, error) {
var cond = builder.NewCond()
@@ -313,9 +316,6 @@ func SyncGrampusQueues(updateList []ResourceQueue, insertList []ResourceQueue, e
if _, err = sess.In("id", deleteSpcIds).Update(&ResourceSpecification{Status: SpecOffShelf}); err != nil {
return err
}
if _, err = sess.In("spec_id", deleteSpcIds).Delete(&ResourceSceneSpec{}); err != nil {
return err
}
}

}


+ 2
- 2
models/resource_scene.go View File

@@ -116,7 +116,7 @@ func InsertResourceScene(r ResourceSceneReq) error {

//check
specs := make([]ResourceSpecification, 0)
cond := builder.In("id", r.SpecIds).And(builder.Eq{"status": SpecOnShelf})
cond := builder.In("id", r.SpecIds)
if err := sess.Where(cond).Find(&specs); err != nil {
return err
}
@@ -175,7 +175,7 @@ func UpdateResourceScene(r ResourceSceneReq) error {
}
//check specification
specs := make([]ResourceSpecification, 0)
cond := builder.In("id", r.SpecIds).And(builder.Eq{"status": SpecOnShelf})
cond := builder.In("id", r.SpecIds)
if err := sess.Where(cond).Find(&specs); err != nil {
return err
}


+ 21
- 8
models/resource_specification.go View File

@@ -12,6 +12,13 @@ const (
SpecOffShelf
)

type SearchSpecOrderBy int

const (
SearchSpecOrderById SearchSpecOrderBy = iota
SearchSpecOrder4Standard
)

type ResourceSpecification struct {
ID int64 `xorm:"pk autoincr"`
QueueId int64 `xorm:"INDEX"`
@@ -85,6 +92,7 @@ type SearchResourceSpecificationOptions struct {
Status int
Cluster string
AvailableCode int
OrderBy SearchSpecOrderBy
}

type SearchResourceBriefSpecificationOptions struct {
@@ -168,6 +176,7 @@ type FindSpecsOptions struct {
UseShareMemGiB bool
//if true,find specs no matter used or not used in scene. if false,only find specs used in scene
RequestAll bool
SpecStatus int
}

type Specification struct {
@@ -232,10 +241,18 @@ func SearchResourceSpecification(opts SearchResourceSpecificationOptions) (int64
return 0, nil, err
}

var orderby = ""
switch opts.OrderBy {
case SearchSpecOrder4Standard:
orderby = "resource_queue.compute_resource asc,resource_queue.acc_card_type asc,resource_specification.acc_cards_num asc,resource_specification.cpu_cores asc,resource_specification.mem_gi_b asc,resource_specification.share_mem_gi_b asc"
default:
orderby = "resource_specification.id desc"
}

r := make([]ResourceSpecAndQueue, 0)
err = x.Where(cond).
Join("INNER", "resource_queue", "resource_queue.ID = resource_specification.queue_id").
Desc("resource_specification.id").
OrderBy(orderby).
Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).
Unscoped().Find(&r)
if err != nil {
@@ -269,10 +286,6 @@ func ResourceSpecOffShelf(id int64) (int64, error) {
}
sess.Close()
}()
//delete scene spec relation
if _, err = sess.Where("spec_id = ?", id).Delete(&ResourceSceneSpec{}); err != nil {
return 0, err
}

param := ResourceSpecification{
Status: SpecOffShelf,
@@ -326,9 +339,6 @@ func SyncGrampusSpecs(updateList []ResourceSpecification, insertList []ResourceS
if _, err = sess.Cols("status", "is_available").In("id", deleteIds).Update(&ResourceSpecification{Status: SpecOffShelf, IsAvailable: false}); err != nil {
return err
}
if _, err = sess.In("spec_id", deleteIds).Delete(&ResourceSceneSpec{}); err != nil {
return err
}
}

//update exists specs
@@ -393,6 +403,9 @@ func FindSpecs(opts FindSpecsOptions) ([]*Specification, error) {
if opts.UseShareMemGiB {
cond = cond.And(builder.Eq{"resource_specification.share_mem_gi_b": opts.ShareMemGiB})
}
if opts.SpecStatus > 0 {
cond = cond.And(builder.Eq{"resource_specification.status": opts.SpecStatus})
}
r := make([]*Specification, 0)
s := x.Where(cond).
Join("INNER", "resource_queue", "resource_queue.id = resource_specification.queue_id")


+ 377
- 227
models/user_business_analysis.go View File

@@ -3,12 +3,15 @@ package models
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"sort"
"strconv"
"strings"
"time"

"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
"xorm.io/builder"
"xorm.io/xorm"
@@ -19,185 +22,6 @@ const (
BATCH_INSERT_SIZE = 50
)

type UserBusinessAnalysisAll struct {
ID int64 `xorm:"pk"`

CountDate int64 `xorm:"pk"`

//action :ActionMergePullRequest // 11
CodeMergeCount int `xorm:"NOT NULL DEFAULT 0"`

//action :ActionCommitRepo // 5
CommitCount int `xorm:"NOT NULL DEFAULT 0"`

//action :ActionCreateIssue // 10
IssueCount int `xorm:"NOT NULL DEFAULT 0"`

//comment table current date
CommentCount int `xorm:"NOT NULL DEFAULT 0"`

//watch table current date
FocusRepoCount int `xorm:"NOT NULL DEFAULT 0"`

//star table current date
StarRepoCount int `xorm:"NOT NULL DEFAULT 0"`

//follow table
WatchedCount int `xorm:"NOT NULL DEFAULT 0"`

// user table
GiteaAgeMonth int `xorm:"NOT NULL DEFAULT 0"`

//
CommitCodeSize int `xorm:"NOT NULL DEFAULT 0"`

//attachement table
CommitDatasetSize int `xorm:"NOT NULL DEFAULT 0"`

//0
CommitModelCount int `xorm:"NOT NULL DEFAULT 0"`

//issue, issueassignees
SolveIssueCount int `xorm:"NOT NULL DEFAULT 0"`

//baike
EncyclopediasCount int `xorm:"NOT NULL DEFAULT 0"`

//user
RegistDate timeutil.TimeStamp `xorm:"NOT NULL"`

//repo
CreateRepoCount int `xorm:"NOT NULL DEFAULT 0"`

//login count, from elk
LoginCount int `xorm:"NOT NULL DEFAULT 0"`

//openi index
OpenIIndex float64 `xorm:"NOT NULL DEFAULT 0"`

//user
Email string `xorm:"NOT NULL"`

//user
Name string `xorm:"NOT 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"`
UserIndexPrimitive float64 `xorm:"NOT NULL DEFAULT 0"`

UserLocation string `xorm:"NULL"`

FocusOtherUser int `xorm:"NOT NULL DEFAULT 0"`
CollectDataset int `xorm:"NOT NULL DEFAULT 0"`
CollectedDataset int `xorm:"NOT NULL DEFAULT 0"`
RecommendDataset int `xorm:"NOT NULL DEFAULT 0"`
CollectImage int `xorm:"NOT NULL DEFAULT 0"`
CollectedImage int `xorm:"NOT NULL DEFAULT 0"`
RecommendImage int `xorm:"NOT NULL DEFAULT 0"`

Phone string `xorm:"NULL"`
InvitationUserNum int `xorm:"NOT NULL DEFAULT 0"`
}

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

//action :ActionMergePullRequest // 11
CodeMergeCount int `xorm:"NOT NULL DEFAULT 0"`

//action :ActionCommitRepo // 5
CommitCount int `xorm:"NOT NULL DEFAULT 0"`

//action :ActionCreateIssue // 6
IssueCount int `xorm:"NOT NULL DEFAULT 0"`

//comment table current date
CommentCount int `xorm:"NOT NULL DEFAULT 0"`

//watch table current date
FocusRepoCount int `xorm:"NOT NULL DEFAULT 0"`

//star table current date
StarRepoCount int `xorm:"NOT NULL DEFAULT 0"`

//follow table
WatchedCount int `xorm:"NOT NULL DEFAULT 0"`

// user table
GiteaAgeMonth int `xorm:"NOT NULL DEFAULT 0"`

//
CommitCodeSize int `xorm:"NOT NULL DEFAULT 0"`

//attachement table
CommitDatasetSize int `xorm:"NOT NULL DEFAULT 0"`

//0
CommitModelCount int `xorm:"NOT NULL DEFAULT 0"`

//issue, issueassignees
SolveIssueCount int `xorm:"NOT NULL DEFAULT 0"`

//baike
EncyclopediasCount int `xorm:"NOT NULL DEFAULT 0"`

//user
RegistDate timeutil.TimeStamp `xorm:"NOT NULL"`

//repo
CreateRepoCount int `xorm:"NOT NULL DEFAULT 0"`

//login count, from elk
LoginCount int `xorm:"NOT NULL DEFAULT 0"`

//openi index
OpenIIndex float64 `xorm:"NOT NULL DEFAULT 0"`

//user
Email string `xorm:"NOT NULL"`

//user
Name string `xorm:"NOT 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"`
UserIndexPrimitive float64 `xorm:"NOT NULL DEFAULT 0"`

UserLocation string `xorm:"NULL"`

FocusOtherUser int `xorm:"NOT NULL DEFAULT 0"`
CollectDataset int `xorm:"NOT NULL DEFAULT 0"`
CollectedDataset int `xorm:"NOT NULL DEFAULT 0"`
RecommendDataset int `xorm:"NOT NULL DEFAULT 0"`
CollectImage int `xorm:"NOT NULL DEFAULT 0"`
CollectedImage int `xorm:"NOT NULL DEFAULT 0"`
RecommendImage int `xorm:"NOT NULL DEFAULT 0"`

Phone string `xorm:"NULL"`
InvitationUserNum int `xorm:"NOT NULL DEFAULT 0"`
}

type UserBusinessAnalysisQueryOptions struct {
ListOptions
UserName string
@@ -499,7 +323,7 @@ func QueryUserStaticDataForUserDefine(opts *UserBusinessAnalysisQueryOptions, wi
DataDate := currentTimeNow.Format("2006-01-02 15:04")

CodeMergeCountMap := queryPullRequest(start_unix, end_unix)
CommitCountMap := queryCommitAction(start_unix, end_unix, 5)
CommitCountMap, _ := queryCommitAction(start_unix, end_unix, 5)
IssueCountMap := queryCreateIssue(start_unix, end_unix)

CommentCountMap := queryComment(start_unix, end_unix)
@@ -517,16 +341,16 @@ func QueryUserStaticDataForUserDefine(opts *UserBusinessAnalysisQueryOptions, wi
CommitCodeSizeMapJson, _ := json.Marshal(CommitCodeSizeMap)
log.Info("CommitCodeSizeMapJson=" + string(CommitCodeSizeMapJson))
}
CommitDatasetSizeMap, CommitDatasetNumMap := queryDatasetSize(start_unix, end_unix)
CommitDatasetSizeMap, CommitDatasetNumMap, _ := queryDatasetSize(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)
OpenIIndexMap := queryUserRepoOpenIIndex(start_unix, end_unix)
CloudBrainTaskMap, CloudBrainTaskItemMap := queryCloudBrainTask(start_unix, end_unix)
AiModelManageMap := queryUserModel(start_unix, end_unix)

CollectDataset, CollectedDataset := queryDatasetStars(start_unix, end_unix)
RecommendDataset := queryRecommedDataSet(start_unix, end_unix)
RecommendDataset, _ := queryRecommedDataSet(start_unix, end_unix)
CollectImage, CollectedImage := queryImageStars(start_unix, end_unix)
RecommendImage := queryRecommedImage(start_unix, end_unix)

@@ -752,7 +576,7 @@ func refreshUserStaticTable(wikiCountMap map[string]int, tableName string, pageS
startTime := currentTimeNow.AddDate(0, 0, -1)

CodeMergeCountMap := queryPullRequest(start_unix, end_unix)
CommitCountMap := queryCommitAction(start_unix, end_unix, 5)
CommitCountMap, mostActiveMap := queryCommitAction(start_unix, end_unix, 5)
IssueCountMap := queryCreateIssue(start_unix, end_unix)

CommentCountMap := queryComment(start_unix, end_unix)
@@ -764,13 +588,13 @@ func refreshUserStaticTable(wikiCountMap map[string]int, tableName string, pageS
log.Info("query commit code errr.")
} else {
log.Info("query commit code size, len=" + fmt.Sprint(len(CommitCodeSizeMap)))
CommitCodeSizeMapJson, _ := json.Marshal(CommitCodeSizeMap)
log.Info("CommitCodeSizeMapJson=" + string(CommitCodeSizeMapJson))
//CommitCodeSizeMapJson, _ := json.Marshal(CommitCodeSizeMap)
//log.Info("CommitCodeSizeMapJson=" + string(CommitCodeSizeMapJson))
}
//CommitCodeSizeMap := queryCommitCodeSize(StartTimeNextDay.Unix(), EndTimeNextDay.Unix())
CommitDatasetSizeMap, CommitDatasetNumMap := queryDatasetSize(start_unix, end_unix)
CommitDatasetSizeMap, CommitDatasetNumMap, dataSetDownloadMap := queryDatasetSize(start_unix, end_unix)
SolveIssueCountMap := querySolveIssue(start_unix, end_unix)
CreateRepoCountMap := queryUserCreateRepo(start_unix, end_unix)
CreateRepoCountMap, DetailInfoMap, MostDownloadMap := queryUserCreateRepo(start_unix, end_unix)
LoginCountMap := queryLoginCount(start_unix, end_unix)

OpenIIndexMap := queryUserRepoOpenIIndex(startTime.Unix(), end_unix)
@@ -778,14 +602,19 @@ func refreshUserStaticTable(wikiCountMap map[string]int, tableName string, pageS
AiModelManageMap := queryUserModel(start_unix, end_unix)

CollectDataset, CollectedDataset := queryDatasetStars(start_unix, end_unix)
RecommendDataset := queryRecommedDataSet(start_unix, end_unix)
RecommendDataset, CreatedDataset := queryRecommedDataSet(start_unix, end_unix)
CollectImage, CollectedImage := queryImageStars(start_unix, end_unix)
RecommendImage := queryRecommedImage(start_unix, end_unix)

InvitationMap := queryUserInvitationCount(start_unix, end_unix)

DataDate := currentTimeNow.Format("2006-01-02") + " 00:01"

bonusMap := make(map[string]map[string]int)
if tableName == "user_business_analysis_current_year" {
bonusMap = getBonusMap()
log.Info("truncate all data from table:user_summary_current_year ")
statictisSess.Exec("TRUNCATE TABLE user_summary_current_year")
}
cond := "type != 1 and is_active=true"
count, err := sess.Where(cond).Count(new(User))
if err != nil {
@@ -883,6 +712,37 @@ func refreshUserStaticTable(wikiCountMap map[string]int, tableName string, pageS
userMetrics["TotalHasActivityUser"] = getMapKeyStringValue("TotalHasActivityUser", userMetrics) + 1
}
}
if tableName == "user_business_analysis_current_year" {
//年度数据
subTime := time.Now().UTC().Sub(dateRecordAll.RegistDate.AsTime().UTC())
mostActiveDay := ""
if userInfo, ok := mostActiveMap[dateRecordAll.ID]; ok {
mostActiveDay = getMostActiveJson(userInfo)
}
scoreMap := make(map[string]float64)
repoInfo := getRepoDetailInfo(DetailInfoMap, dateRecordAll.ID, MostDownloadMap)
dataSetInfo, datasetscore := getDataSetInfo(dateRecordAll.ID, CreatedDataset, dataSetDownloadMap, CommitDatasetNumMap, CollectedDataset)
scoreMap["datasetscore"] = datasetscore
codeInfo, codescore := getCodeInfo(dateRecordAll)
scoreMap["codescore"] = codescore
cloudBrainInfo := getCloudBrainInfo(dateRecordAll, CloudBrainTaskItemMap, scoreMap)
playARoll := getPlayARoll(bonusMap, dateRecordAll.Name, scoreMap)
re := &UserSummaryCurrentYear{
ID: dateRecordAll.ID,
Name: dateRecordAll.Name,
Email: dateRecordAll.Email,
Phone: dateRecordAll.Phone,
RegistDate: dateRecordAll.RegistDate,
DateCount: int(subTime.Hours()) / 24,
MostActiveDay: mostActiveDay,
RepoInfo: repoInfo,
DataSetInfo: dataSetInfo,
CodeInfo: codeInfo,
CloudBrainInfo: cloudBrainInfo,
PlayARoll: playARoll,
}
statictisSess.Insert(re)
}
}
if len(dateRecordBatch) > 0 {
err := insertTable(dateRecordBatch, tableName, statictisSess)
@@ -890,6 +750,7 @@ func refreshUserStaticTable(wikiCountMap map[string]int, tableName string, pageS
if err != nil {
log.Info("insert all data failed." + err.Error())
}

}
indexTotal += PAGE_SIZE
if indexTotal >= count {
@@ -911,6 +772,204 @@ func refreshUserStaticTable(wikiCountMap map[string]int, tableName string, pageS
log.Info("refresh data finished.tableName=" + tableName + " total record:" + fmt.Sprint(insertCount))
}

func getBonusMap() map[string]map[string]int {
bonusMap := make(map[string]map[string]int)
url := setting.RecommentRepoAddr + "bonus/record.txt"
content, err := GetContentFromPromote(url)
if err == nil {
filenames := strings.Split(content, "\n")
for i := 0; i < len(filenames); i++ {
url = setting.RecommentRepoAddr + "bonus/" + filenames[i]
csvContent, err1 := GetContentFromPromote(url)
if err1 == nil {
//read csv
lines := strings.Split(csvContent, "\n")
for j := 1; j < len(lines); j++ {
aLine := strings.Split(lines[j], ",")
if len(aLine) < 7 {
continue
}
userName := aLine[1]
//email := lines[2]
record, ok := bonusMap[userName]
if !ok {
record = make(map[string]int)
}
record["times"] = getMapKeyStringValue("times", record) + getIntValue(aLine[3])
record["total_bonus"] = getMapKeyStringValue("total_bonus", record) + getIntValue(aLine[4])
record["total_cardtime"] = getMapKeyStringValue("total_cardtime", record) + getIntValue(aLine[5])
record["total_giveup"] = getMapKeyStringValue("total_giveup", record) + getIntValue(aLine[6])
}
}
}
}
return bonusMap
}

func getIntValue(val string) int {
i, err := strconv.Atoi(val)
if err == nil {
return i
}
return 0
}

func getPlayARoll(bonusMap map[string]map[string]int, userName string, scoreMap map[string]float64) string {
bonusInfo := make(map[string]string)
record, ok := bonusMap[userName]
if ok {
rollscore := 0.0
bonusInfo["times"] = fmt.Sprint(record["times"])
if record["times"] >= 4 {
rollscore = float64(record["times"]) / float64(4)
}
scoreMap["rollscore"] = rollscore
bonusInfo["total_bonus"] = fmt.Sprint(record["total_bonus"])
bonusInfo["total_cardtime"] = fmt.Sprint(record["total_cardtime"])
bonusInfo["total_giveup"] = fmt.Sprint(record["total_giveup"])
bonusInfoJson, _ := json.Marshal(bonusInfo)
return string(bonusInfoJson)
} else {
return ""
}
}

func getCloudBrainInfo(dateRecordAll UserBusinessAnalysisAll, CloudBrainTaskItemMap map[string]int, scoreMap map[string]float64) string {
trainscore := 0.0
debugscore := 0.0
runtime := 0.0
if dateRecordAll.CloudBrainTaskNum > 0 {
cloudBrainInfo := make(map[string]string)
cloudBrainInfo["create_task_num"] = fmt.Sprint(dateRecordAll.CloudBrainTaskNum)
cloudBrainInfo["debug_task_num"] = fmt.Sprint(dateRecordAll.GpuDebugJob + dateRecordAll.NpuDebugJob)
if dateRecordAll.GpuDebugJob+dateRecordAll.NpuDebugJob >= 50 {
debugscore = float64(dateRecordAll.GpuDebugJob+dateRecordAll.NpuDebugJob) / float64(50)
}
cloudBrainInfo["train_task_num"] = fmt.Sprint(dateRecordAll.GpuTrainJob + dateRecordAll.NpuTrainJob)
if dateRecordAll.GpuTrainJob+dateRecordAll.NpuTrainJob >= 50 {
trainscore = float64(dateRecordAll.GpuTrainJob+dateRecordAll.NpuTrainJob) / float64(50)
}
cloudBrainInfo["inference_task_num"] = fmt.Sprint(dateRecordAll.NpuInferenceJob + CloudBrainTaskItemMap[fmt.Sprint(dateRecordAll.ID)+"_GpuInferenceJob"])
cloudBrainInfo["card_runtime"] = fmt.Sprint(dateRecordAll.CloudBrainRunTime)
if dateRecordAll.CloudBrainRunTime >= 100 {
runtime = float64(dateRecordAll.CloudBrainRunTime) / float64(100)
}
cloudBrainInfo["card_runtime_money"] = fmt.Sprint(dateRecordAll.CloudBrainRunTime * 5)
cloudBrainInfo["CloudBrainOne"] = fmt.Sprint(CloudBrainTaskItemMap[fmt.Sprint(dateRecordAll.ID)+"_CloudBrainOne"])
cloudBrainInfo["CloudBrainTwo"] = fmt.Sprint(CloudBrainTaskItemMap[fmt.Sprint(dateRecordAll.ID)+"_CloudBrainTwo"])
cloudBrainInfo["C2Net"] = fmt.Sprint(CloudBrainTaskItemMap[fmt.Sprint(dateRecordAll.ID)+"_C2Net"])

cloudBrainInfoJson, _ := json.Marshal(cloudBrainInfo)
scoreMap["trainscore"] = trainscore
scoreMap["debugscore"] = debugscore
scoreMap["runtime"] = runtime
return string(cloudBrainInfoJson)
} else {
scoreMap["trainscore"] = trainscore
scoreMap["debugscore"] = debugscore
scoreMap["runtime"] = runtime
return ""
}
}

func getCodeInfo(dateRecordAll UserBusinessAnalysisAll) (string, float64) {
if dateRecordAll.CommitCount > 0 {
codeInfo := make(map[string]string)
codeInfo["commit_count"] = fmt.Sprint(dateRecordAll.CommitCount)
codeInfo["commit_line"] = fmt.Sprint(dateRecordAll.CommitCodeSize)
score := 0.0
score = float64(dateRecordAll.CommitCodeSize) / float64(dateRecordAll.CommitCount) / float64(20000)
if score < (float64(dateRecordAll.CommitCount) / float64(100)) {
score = float64(dateRecordAll.CommitCount) / float64(100)
}
codeInfo["score"] = fmt.Sprintf("%.2f", score)

codeInfoJson, _ := json.Marshal(codeInfo)
return string(codeInfoJson), score
} else {
return "", 0
}
}

func getDataSetInfo(userId int64, CreatedDataset map[int64]int, dataSetDownloadMap map[int64]int, CommitDatasetNumMap map[int64]int, CollectedDataset map[int64]int) (string, float64) {
datasetInfo := make(map[string]string)
score := 0.0
if create_count, ok := CreatedDataset[userId]; ok {
datasetInfo["create_count"] = fmt.Sprint(create_count)
score = float64(create_count) / 10
}
if upload_count, ok := CommitDatasetNumMap[userId]; ok {
datasetInfo["upload_file_count"] = fmt.Sprint(upload_count)
}
if download_count, ok := dataSetDownloadMap[userId]; ok {
datasetInfo["download_count"] = fmt.Sprint(download_count)
}
if cllected_count, ok := CollectedDataset[userId]; ok {
datasetInfo["cllected_count"] = fmt.Sprint(cllected_count)
}

if len(datasetInfo) > 0 {
datasetInfoJson, _ := json.Marshal(datasetInfo)
return string(datasetInfoJson), score
} else {
return "", score
}
}

func getRepoDetailInfo(repoDetailInfoMap map[string]int, userId int64, mostDownload map[int64]string) string {
repoDetailInfo := make(map[string]string)
if total, ok := repoDetailInfoMap[fmt.Sprint(userId)+"_total"]; ok {
repoDetailInfo["repo_total"] = fmt.Sprint(total)
}
if private, ok := repoDetailInfoMap[fmt.Sprint(userId)+"_is_private"]; ok {
repoDetailInfo["repo_is_private"] = fmt.Sprint(private)
}
if public, ok := repoDetailInfoMap[fmt.Sprint(userId)+"_is_public"]; ok {
repoDetailInfo["repo_is_public"] = fmt.Sprint(public)
}
if download, ok := repoDetailInfoMap[fmt.Sprint(userId)+"_total_download"]; ok {
repoDetailInfo["repo_total_download"] = fmt.Sprint(download)
}
if mostdownload, ok := repoDetailInfoMap[fmt.Sprint(userId)+"_most_download"]; ok {
repoDetailInfo["repo_most_download_count"] = fmt.Sprint(mostdownload)
}
if mostdownloadName, ok := mostDownload[userId]; ok {
repoDetailInfo["repo_most_download_name"] = mostdownloadName
}
if len(repoDetailInfo) > 0 {
repoDetailInfoJson, _ := json.Marshal(repoDetailInfo)
return string(repoDetailInfoJson)
} else {
return ""
}
}

func getMostActiveJson(userInfo map[string]int) string {
mostActiveMap := make(map[string]string)
if day, ok := userInfo["hour_day"]; ok {
hour := userInfo["hour_hour"]
month := userInfo["hour_month"]
year := userInfo["hour_year"]
delete(userInfo, "hour_day")
delete(userInfo, "hour_hour")
delete(userInfo, "hour_month")
delete(userInfo, "hour_year")
mostActiveMap["before_dawn"] = fmt.Sprint(year) + "/" + fmt.Sprint(month) + "/" + fmt.Sprint(day) + " " + fmt.Sprint(hour)
}
max := 0
max_day := ""
for key, value := range userInfo {
if value > max {
max = value
max_day = key
}
}
mostActiveMap["most_active_day"] = max_day
mostActiveMap["most_active_num"] = fmt.Sprint(max)
mostActiveMapJson, _ := json.Marshal(mostActiveMap)
return string(mostActiveMapJson)
}

func updateUserIndex(tableName string, statictisSess *xorm.Session, userId int64, userIndex float64) {
updateSql := "UPDATE public." + tableName + " set user_index=" + fmt.Sprint(userIndex*100) + " where id=" + fmt.Sprint(userId)
statictisSess.Exec(updateSql)
@@ -997,7 +1056,7 @@ func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time,

DataDate := CountDate.Format("2006-01-02")
CodeMergeCountMap := queryPullRequest(start_unix, end_unix)
CommitCountMap := queryCommitAction(start_unix, end_unix, 5)
CommitCountMap, _ := queryCommitAction(start_unix, end_unix, 5)
IssueCountMap := queryCreateIssue(start_unix, end_unix)

CommentCountMap := queryComment(start_unix, end_unix)
@@ -1010,19 +1069,19 @@ func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time,
log.Info("query commit code errr.")
} else {
//log.Info("query commit code size, len=" + fmt.Sprint(len(CommitCodeSizeMap)))
CommitCodeSizeMapJson, _ := json.Marshal(CommitCodeSizeMap)
log.Info("CommitCodeSizeMapJson=" + string(CommitCodeSizeMapJson))
//CommitCodeSizeMapJson, _ := json.Marshal(CommitCodeSizeMap)
//log.Info("CommitCodeSizeMapJson=" + string(CommitCodeSizeMapJson))
}
CommitDatasetSizeMap, CommitDatasetNumMap := queryDatasetSize(start_unix, end_unix)
CommitDatasetSizeMap, CommitDatasetNumMap, _ := queryDatasetSize(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)
OpenIIndexMap := queryUserRepoOpenIIndex(start_unix, end_unix)
CloudBrainTaskMap, CloudBrainTaskItemMap := queryCloudBrainTask(start_unix, end_unix)
AiModelManageMap := queryUserModel(start_unix, end_unix)

CollectDataset, CollectedDataset := queryDatasetStars(start_unix, end_unix)
RecommendDataset := queryRecommedDataSet(start_unix, end_unix)
RecommendDataset, _ := queryRecommedDataSet(start_unix, end_unix)
CollectImage, CollectedImage := queryImageStars(start_unix, end_unix)
RecommendImage := queryRecommedImage(start_unix, end_unix)

@@ -1490,41 +1549,65 @@ func queryPullRequest(start_unix int64, end_unix int64) map[int64]int {
return resultMap
}

func queryCommitAction(start_unix int64, end_unix int64, actionType int64) map[int64]int {
func queryCommitAction(start_unix int64, end_unix int64, actionType int64) (map[int64]int, map[int64]map[string]int) {
sess := x.NewSession()
defer sess.Close()
resultMap := make(map[int64]int)
cond := "user_id=act_user_id and op_type=" + fmt.Sprint(actionType) + " and created_unix>=" + fmt.Sprint(start_unix) + " and created_unix<=" + fmt.Sprint(end_unix)
mostActiveMap := make(map[int64]map[string]int)
cond := "user_id=act_user_id and created_unix>=" + fmt.Sprint(start_unix) + " and created_unix<=" + fmt.Sprint(end_unix)

count, err := sess.Where(cond).Count(new(Action))
if err != nil {
log.Info("query action error. return.")
return resultMap
return resultMap, mostActiveMap
}

var indexTotal int64
indexTotal = 0
for {
sess.Select("id,user_id,op_type,act_user_id").Table("action").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal))
sess.Select("id,user_id,op_type,act_user_id,created_unix").Table("action").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal))
actionList := make([]*Action, 0)
sess.Find(&actionList)

log.Info("query action size=" + fmt.Sprint(len(actionList)))
for _, actionRecord := range actionList {
if _, ok := resultMap[actionRecord.UserID]; !ok {
resultMap[actionRecord.UserID] = 1
if int64(actionRecord.OpType) == actionType {
if _, ok := resultMap[actionRecord.UserID]; !ok {
resultMap[actionRecord.UserID] = 1
} else {
resultMap[actionRecord.UserID] += 1
}
}
key := getDate(actionRecord.CreatedUnix)
if _, ok := mostActiveMap[actionRecord.UserID]; !ok {
tmpMap := make(map[string]int)
tmpMap[key] = 1
mostActiveMap[actionRecord.UserID] = tmpMap
} else {
resultMap[actionRecord.UserID] += 1
mostActiveMap[actionRecord.UserID][key] = getMapKeyStringValue(key, mostActiveMap[actionRecord.UserID]) + 1
}
utcTime := actionRecord.CreatedUnix.AsTime()
hour := utcTime.Hour()
if hour >= 0 && hour <= 5 {
key = "hour_hour"
if getMapKeyStringValue(key, mostActiveMap[actionRecord.UserID]) < hour {
mostActiveMap[actionRecord.UserID][key] = hour
mostActiveMap[actionRecord.UserID]["hour_day"] = utcTime.Day()
mostActiveMap[actionRecord.UserID]["hour_month"] = int(utcTime.Month())
mostActiveMap[actionRecord.UserID]["hour_year"] = utcTime.Year()
}
}
}

indexTotal += PAGE_SIZE
if indexTotal >= count {
break
}
}

return resultMap
return resultMap, mostActiveMap
}
func getDate(createTime timeutil.TimeStamp) string {
return createTime.Format("2006-01-02")
}

func queryCreateIssue(start_unix int64, end_unix int64) map[int64]int {
@@ -1714,15 +1797,16 @@ func queryFollow(start_unix int64, end_unix int64) (map[int64]int, map[int64]int
return resultMap, resultFocusedByOtherMap
}

func queryRecommedDataSet(start_unix int64, end_unix int64) map[int64]int {
func queryRecommedDataSet(start_unix int64, end_unix int64) (map[int64]int, map[int64]int) {
sess := x.NewSession()
defer sess.Close()
userIdDdatasetMap := make(map[int64]int)
cond := " created_unix>=" + fmt.Sprint(start_unix) + " and created_unix<=" + fmt.Sprint(end_unix) + " and recommend=true"
userIdRecommentDatasetMap := make(map[int64]int)
userIdCreateDatasetMap := 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(Dataset))
if err != nil {
log.Info("query recommend dataset error. return.")
return userIdDdatasetMap
return userIdRecommentDatasetMap, userIdCreateDatasetMap
}
var indexTotal int64
indexTotal = 0
@@ -1732,18 +1816,21 @@ func queryRecommedDataSet(start_unix int64, end_unix int64) map[int64]int {
sess.Find(&datasetList)
log.Info("query datasetList size=" + fmt.Sprint(len(datasetList)))
for _, datasetRecord := range datasetList {
if _, ok := userIdDdatasetMap[datasetRecord.UserID]; !ok {
userIdDdatasetMap[datasetRecord.UserID] = 1
} else {
userIdDdatasetMap[datasetRecord.UserID] += 1
if datasetRecord.Recommend {
if _, ok := userIdRecommentDatasetMap[datasetRecord.UserID]; !ok {
userIdRecommentDatasetMap[datasetRecord.UserID] = 1
} else {
userIdRecommentDatasetMap[datasetRecord.UserID] += 1
}
}
userIdCreateDatasetMap[datasetRecord.UserID] = getMapValue(datasetRecord.UserID, userIdCreateDatasetMap) + 1
}
indexTotal += PAGE_SIZE
if indexTotal >= count {
break
}
}
return userIdDdatasetMap
return userIdRecommentDatasetMap, userIdCreateDatasetMap
}

func queryAllDataSet() (map[int64]int64, map[int64]int64) {
@@ -1922,22 +2009,23 @@ func queryImageStars(start_unix int64, end_unix int64) (map[int64]int, map[int64
return imageCollect, imageCollected
}

func queryDatasetSize(start_unix int64, end_unix int64) (map[int64]int, map[int64]int) {
func queryDatasetSize(start_unix int64, end_unix int64) (map[int64]int, map[int64]int, map[int64]int) {
sess := x.NewSession()
defer sess.Close()
resultSizeMap := make(map[int64]int)
resultNumMap := make(map[int64]int)
resultDownloadMap := 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(Attachment))
if err != nil {
log.Info("query attachment error. return.")
return resultSizeMap, resultNumMap
return resultSizeMap, resultNumMap, resultDownloadMap
}
var indexTotal int64
indexTotal = 0
for {
sess.Select("id,uploader_id,size").Table("attachment").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal))
sess.Select("id,uploader_id,size,download_count").Table("attachment").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal))
attachmentList := make([]*Attachment, 0)
sess.Find(&attachmentList)

@@ -1946,9 +2034,11 @@ func queryDatasetSize(start_unix int64, end_unix int64) (map[int64]int, map[int6
if _, ok := resultSizeMap[attachRecord.UploaderID]; !ok {
resultSizeMap[attachRecord.UploaderID] = int(attachRecord.Size / (1024 * 1024)) //MB
resultNumMap[attachRecord.UploaderID] = 1
resultDownloadMap[attachRecord.UploaderID] = int(attachRecord.DownloadCount)
} else {
resultSizeMap[attachRecord.UploaderID] += int(attachRecord.Size / (1024 * 1024)) //MB
resultNumMap[attachRecord.UploaderID] += 1
resultDownloadMap[attachRecord.UploaderID] += int(attachRecord.DownloadCount)
}
}

@@ -1958,32 +2048,50 @@ func queryDatasetSize(start_unix int64, end_unix int64) (map[int64]int, map[int6
}
}

return resultSizeMap, resultNumMap
return resultSizeMap, resultNumMap, resultDownloadMap
}

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

detailInfoMap := make(map[string]int)
mostDownloadMap := make(map[int64]string)

cond := "is_fork=false and created_unix>=" + fmt.Sprint(start_unix) + " and created_unix<=" + fmt.Sprint(end_unix)
count, err := sess.Where(cond).Count(new(Repository))
if err != nil {
log.Info("query Repository error. return.")
return resultMap
return resultMap, detailInfoMap, mostDownloadMap
}
var indexTotal int64
indexTotal = 0
for {
sess.Select("id,owner_id,name").Table("repository").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal))
sess.Select("id,owner_id,name,is_private,clone_cnt").Table("repository").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal))
repoList := make([]*Repository, 0)
sess.Find(&repoList)
log.Info("query Repository size=" + fmt.Sprint(len(repoList)))
for _, repoRecord := range repoList {
if _, ok := resultMap[repoRecord.OwnerID]; !ok {
resultMap[repoRecord.OwnerID] = 1
resultMap[repoRecord.OwnerID] = getMapValue(repoRecord.OwnerID, resultMap) + 1

key := fmt.Sprint(repoRecord.OwnerID) + "_total"
detailInfoMap[key] = getMapKeyStringValue(key, detailInfoMap) + 1

if repoRecord.IsPrivate {
key := fmt.Sprint(repoRecord.OwnerID) + "_is_private"
detailInfoMap[key] = getMapKeyStringValue(key, detailInfoMap) + 1
} else {
resultMap[repoRecord.OwnerID] += 1
key := fmt.Sprint(repoRecord.OwnerID) + "_is_public"
detailInfoMap[key] = getMapKeyStringValue(key, detailInfoMap) + 1
}
key = fmt.Sprint(repoRecord.OwnerID) + "_total_download"
detailInfoMap[key] = getMapKeyStringValue(key, detailInfoMap) + int(repoRecord.CloneCnt)

key = fmt.Sprint(repoRecord.OwnerID) + "_most_download"
if int(repoRecord.CloneCnt) > getMapKeyStringValue(key, detailInfoMap) {
detailInfoMap[key] = int(repoRecord.CloneCnt)
mostDownloadMap[repoRecord.OwnerID] = repoRecord.DisplayName()
}
}
indexTotal += PAGE_SIZE
@@ -1992,7 +2100,7 @@ func queryUserCreateRepo(start_unix int64, end_unix int64) map[int64]int {
}
}

return resultMap
return resultMap, detailInfoMap, mostDownloadMap
}

func queryUserRepoOpenIIndex(start_unix int64, end_unix int64) map[int64]float64 {
@@ -2180,6 +2288,7 @@ func queryCloudBrainTask(start_unix int64, end_unix int64) (map[int64]int, map[s
setMapKey("CloudBrainRunTime", cloudTaskRecord.UserID, int(cloudTaskRecord.Duration), resultItemMap)
}
if cloudTaskRecord.Type == 1 { //npu
setMapKey("CloudBrainTwo", cloudTaskRecord.UserID, 1, resultItemMap)
if cloudTaskRecord.JobType == "TRAIN" {
setMapKey("NpuTrainJob", cloudTaskRecord.UserID, 1, resultItemMap)
} else if cloudTaskRecord.JobType == "INFERENCE" {
@@ -2187,14 +2296,32 @@ func queryCloudBrainTask(start_unix int64, end_unix int64) (map[int64]int, map[s
} else {
setMapKey("NpuDebugJob", cloudTaskRecord.UserID, 1, resultItemMap)
}
} else { //type=0 gpu
} else if cloudTaskRecord.Type == 0 { //type=0 gpu
setMapKey("CloudBrainOne", cloudTaskRecord.UserID, 1, resultItemMap)
if cloudTaskRecord.JobType == "TRAIN" {
setMapKey("GpuTrainJob", cloudTaskRecord.UserID, 1, resultItemMap)
} else if cloudTaskRecord.JobType == "INFERENCE" {
setMapKey("GpuInferenceJob", cloudTaskRecord.UserID, 1, resultItemMap)
} else if cloudTaskRecord.JobType == "BENCHMARK" {
setMapKey("GpuBenchMarkJob", cloudTaskRecord.UserID, 1, resultItemMap)
} else {
setMapKey("GpuDebugJob", cloudTaskRecord.UserID, 1, resultItemMap)
}
} else if cloudTaskRecord.Type == 2 {
setMapKey("C2Net", cloudTaskRecord.UserID, 1, resultItemMap)
if cloudTaskRecord.ComputeResource == NPUResource {
if cloudTaskRecord.JobType == "TRAIN" {
setMapKey("NpuTrainJob", cloudTaskRecord.UserID, 1, resultItemMap)
} else {
setMapKey("NpuDebugJob", cloudTaskRecord.UserID, 1, resultItemMap)
}
} else if cloudTaskRecord.ComputeResource == GPUResource {
if cloudTaskRecord.JobType == "TRAIN" {
setMapKey("GpuTrainJob", cloudTaskRecord.UserID, 1, resultItemMap)
} else {
setMapKey("GpuDebugJob", cloudTaskRecord.UserID, 1, resultItemMap)
}
}
}
}
indexTotal += PAGE_SIZE
@@ -2274,3 +2401,26 @@ func subMonth(t1, t2 time.Time) (month int) {
}
return month
}

func GetContentFromPromote(url string) (string, error) {
defer func() {
if err := recover(); err != nil {
log.Info("not error.", err)
return
}
}()
resp, err := http.Get(url)
if err != nil || resp.StatusCode != 200 {
log.Info("Get organizations url error=" + err.Error())
return "", err
}

bytes, err := ioutil.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
log.Info("Get organizations url error=" + err.Error())
return "", err
}
allLineStr := string(bytes)
return allLineStr, nil
}

+ 200
- 0
models/user_business_struct.go View File

@@ -2,6 +2,27 @@ package models

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

type UserSummaryCurrentYear struct {
ID int64 `xorm:"pk"`
Email string `xorm:"NOT NULL"`
//user
Name string `xorm:"NOT NULL"`
Phone string `xorm:"NULL"`
//user
RegistDate timeutil.TimeStamp `xorm:"NOT NULL"`

DateCount int `xorm:"NOT NULL DEFAULT 0"`
MostActiveDay string `xorm:" NULL "` //08.05
RepoInfo string `xorm:"varchar(1000)"` //创建了XX 个项目,公开项目XX 个,私有项目XX 个累计被下载XXX 次,其中《XXXXXXX 》项目,获得了最高XXX 次下载
DataSetInfo string `xorm:"varchar(500)"` //创建了XX 个数据集,上传了XX 个数据集文件,累计被下载XX 次,被收藏XX 次
CodeInfo string `xorm:"varchar(500)"` //代码提交次数,提交总代码行数,最晚的提交时间
CloudBrainInfo string `xorm:"varchar(1000)"` //,创建了XX 个云脑任务,调试任务XX 个,训练任务XX 个,推理任务XX 个,累计运行了XXXX 卡时,累计节省xxxxx 元
//这些免费的算力资源分别有,XX% 来自鹏城云脑1,XX% 来自鹏城云脑2,XX% 来自智算网络
PlayARoll string `xorm:"varchar(500)"` //你参加了XX 次“我为开源打榜狂”活动,累计上榜XX 次,总共获得了社区XXX 元的激励

Label string `xorm:"varchar(500)"`
}

type UserBusinessAnalysisCurrentYear struct {
ID int64 `xorm:"pk"`
CountDate int64 `xorm:"pk"`
@@ -505,3 +526,182 @@ type UserMetrics struct {
ActivityUserJson string `xorm:"text NULL"` //激活用户列表
CurrentDayRegistUser int `xorm:"NOT NULL DEFAULT 0"` //当天注册用户
}

type UserBusinessAnalysisAll struct {
ID int64 `xorm:"pk"`

CountDate int64 `xorm:"pk"`

//action :ActionMergePullRequest // 11
CodeMergeCount int `xorm:"NOT NULL DEFAULT 0"`

//action :ActionCommitRepo // 5
CommitCount int `xorm:"NOT NULL DEFAULT 0"`

//action :ActionCreateIssue // 10
IssueCount int `xorm:"NOT NULL DEFAULT 0"`

//comment table current date
CommentCount int `xorm:"NOT NULL DEFAULT 0"`

//watch table current date
FocusRepoCount int `xorm:"NOT NULL DEFAULT 0"`

//star table current date
StarRepoCount int `xorm:"NOT NULL DEFAULT 0"`

//follow table
WatchedCount int `xorm:"NOT NULL DEFAULT 0"`

// user table
GiteaAgeMonth int `xorm:"NOT NULL DEFAULT 0"`

//
CommitCodeSize int `xorm:"NOT NULL DEFAULT 0"`

//attachement table
CommitDatasetSize int `xorm:"NOT NULL DEFAULT 0"`

//0
CommitModelCount int `xorm:"NOT NULL DEFAULT 0"`

//issue, issueassignees
SolveIssueCount int `xorm:"NOT NULL DEFAULT 0"`

//baike
EncyclopediasCount int `xorm:"NOT NULL DEFAULT 0"`

//user
RegistDate timeutil.TimeStamp `xorm:"NOT NULL"`

//repo
CreateRepoCount int `xorm:"NOT NULL DEFAULT 0"`

//login count, from elk
LoginCount int `xorm:"NOT NULL DEFAULT 0"`

//openi index
OpenIIndex float64 `xorm:"NOT NULL DEFAULT 0"`

//user
Email string `xorm:"NOT NULL"`

//user
Name string `xorm:"NOT 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"`
UserIndexPrimitive float64 `xorm:"NOT NULL DEFAULT 0"`

UserLocation string `xorm:"NULL"`

FocusOtherUser int `xorm:"NOT NULL DEFAULT 0"`
CollectDataset int `xorm:"NOT NULL DEFAULT 0"`
CollectedDataset int `xorm:"NOT NULL DEFAULT 0"`
RecommendDataset int `xorm:"NOT NULL DEFAULT 0"`
CollectImage int `xorm:"NOT NULL DEFAULT 0"`
CollectedImage int `xorm:"NOT NULL DEFAULT 0"`
RecommendImage int `xorm:"NOT NULL DEFAULT 0"`

Phone string `xorm:"NULL"`
InvitationUserNum int `xorm:"NOT NULL DEFAULT 0"`
}

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

//action :ActionMergePullRequest // 11
CodeMergeCount int `xorm:"NOT NULL DEFAULT 0"`

//action :ActionCommitRepo // 5
CommitCount int `xorm:"NOT NULL DEFAULT 0"`

//action :ActionCreateIssue // 6
IssueCount int `xorm:"NOT NULL DEFAULT 0"`

//comment table current date
CommentCount int `xorm:"NOT NULL DEFAULT 0"`

//watch table current date
FocusRepoCount int `xorm:"NOT NULL DEFAULT 0"`

//star table current date
StarRepoCount int `xorm:"NOT NULL DEFAULT 0"`

//follow table
WatchedCount int `xorm:"NOT NULL DEFAULT 0"`

// user table
GiteaAgeMonth int `xorm:"NOT NULL DEFAULT 0"`

//
CommitCodeSize int `xorm:"NOT NULL DEFAULT 0"`

//attachement table
CommitDatasetSize int `xorm:"NOT NULL DEFAULT 0"`

//0
CommitModelCount int `xorm:"NOT NULL DEFAULT 0"`

//issue, issueassignees
SolveIssueCount int `xorm:"NOT NULL DEFAULT 0"`

//baike
EncyclopediasCount int `xorm:"NOT NULL DEFAULT 0"`

//user
RegistDate timeutil.TimeStamp `xorm:"NOT NULL"`

//repo
CreateRepoCount int `xorm:"NOT NULL DEFAULT 0"`

//login count, from elk
LoginCount int `xorm:"NOT NULL DEFAULT 0"`

//openi index
OpenIIndex float64 `xorm:"NOT NULL DEFAULT 0"`

//user
Email string `xorm:"NOT NULL"`

//user
Name string `xorm:"NOT 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"`
UserIndexPrimitive float64 `xorm:"NOT NULL DEFAULT 0"`

UserLocation string `xorm:"NULL"`

FocusOtherUser int `xorm:"NOT NULL DEFAULT 0"`
CollectDataset int `xorm:"NOT NULL DEFAULT 0"`
CollectedDataset int `xorm:"NOT NULL DEFAULT 0"`
RecommendDataset int `xorm:"NOT NULL DEFAULT 0"`
CollectImage int `xorm:"NOT NULL DEFAULT 0"`
CollectedImage int `xorm:"NOT NULL DEFAULT 0"`
RecommendImage int `xorm:"NOT NULL DEFAULT 0"`

Phone string `xorm:"NULL"`
InvitationUserNum int `xorm:"NOT NULL DEFAULT 0"`
}

+ 26
- 0
modules/grampus/resty.go View File

@@ -245,6 +245,32 @@ func GetTrainJobLog(jobID string) (string, error) {
return logContent, nil
}

func GetGrampusMetrics(jobID string) (models.GetTrainJobMetricStatisticResult, error) {
checkSetting()
client := getRestyClient()
var result models.GetTrainJobMetricStatisticResult
res, err := client.R().
SetAuthToken(TOKEN).
Get(HOST + urlTrainJob + "/" + jobID + "/task/0/replica/0/metrics")

if err != nil {
return result, fmt.Errorf("resty GetTrainJobLog: %v", err)
}
if err = json.Unmarshal([]byte(res.String()), &result); err != nil {
log.Error("GetGrampusMetrics json.Unmarshal failed(%s): %v", res.String(), err.Error())
return result, fmt.Errorf("json.Unmarshal failed(%s): %v", res.String(), err.Error())
}
if res.StatusCode() != http.StatusOK {
log.Error("Call GrampusMetrics failed(%d):%s(%s)", res.StatusCode(), result.ErrorCode, result.ErrorMsg)
return result, fmt.Errorf("Call GrampusMetrics failed(%d):%d(%s)", res.StatusCode(), result.ErrorCode, result.ErrorMsg)
}
if !result.IsSuccess {
log.Error("GetGrampusMetrics(%s) failed", jobID)
return result, fmt.Errorf("GetGrampusMetrics failed:%s", result.ErrorMsg)
}
return result, nil
}

func StopJob(jobID string) (*models.GrampusStopJobResponse, error) {
checkSetting()
client := getRestyClient()


+ 27
- 13
modules/setting/setting.go View File

@@ -598,20 +598,23 @@ var (

//grampus config
Grampus = struct {
Env string
Host string
UserName string
Password string
SpecialPools string
C2NetSequence string
SyncScriptProject string
LocalCenterID string
AiCenterInfo string
Env string
Host string
UserName string
Password string
SpecialPools string
C2NetSequence string
SyncScriptProject string
LocalCenterID string
AiCenterInfo string
AiCenterCodeAndNameInfo string
UsageRateBeginTime string
}{}

C2NetInfos *C2NetSqInfos
CenterInfos *AiCenterInfos
C2NetMapInfo map[string]*C2NetSequenceInfo
C2NetInfos *C2NetSqInfos
CenterInfos *AiCenterInfos
C2NetMapInfo map[string]*C2NetSequenceInfo
AiCenterCodeAndNameMapInfo map[string]*C2NetSequenceInfo

//elk config
ElkUrl string
@@ -1466,7 +1469,7 @@ func NewContext() {
MaxDuration = sec.Key("MAX_DURATION").MustInt64(14400)
TrainGpuTypes = sec.Key("TRAIN_GPU_TYPES").MustString("")
TrainResourceSpecs = sec.Key("TRAIN_RESOURCE_SPECS").MustString("")
MaxModelSize = sec.Key("MAX_MODEL_SIZE").MustFloat64(500)
MaxModelSize = sec.Key("MAX_MODEL_SIZE").MustFloat64(200)
InferenceGpuTypes = sec.Key("INFERENCE_GPU_TYPES").MustString("")
InferenceResourceSpecs = sec.Key("INFERENCE_RESOURCE_SPECS").MustString("")
SpecialPools = sec.Key("SPECIAL_POOL").MustString("")
@@ -1680,6 +1683,8 @@ func getGrampusConfig() {
Grampus.Password = sec.Key("PASSWORD").MustString("")
Grampus.SpecialPools = sec.Key("SPECIAL_POOL").MustString("")
Grampus.C2NetSequence = sec.Key("C2NET_SEQUENCE").MustString("{\"sequence\":[{\"id\":1,\"name\":\"cloudbrain_one\",\"content\":\"鹏城云脑一号\",\"content_en\":\"Pencheng Cloudbrain Ⅰ\"},{\"id\":2,\"name\":\"cloudbrain_two\",\"content\":\"鹏城云脑二号\",\"content_en\":\"Pencheng Cloudbrain Ⅱ\"},{\"id\":3,\"name\":\"beida\",\"content\":\"北大人工智能集群系统\",\"content_en\":\"Peking University AI Center\"},{\"id\":4,\"name\":\"hefei\",\"content\":\"合肥类脑智能开放平台\",\"content_en\":\"Hefei AI Center\"},{\"id\":5,\"name\":\"wuhan\",\"content\":\"武汉人工智能计算中心\",\"content_en\":\"Wuhan AI Center\"},{\"id\":6,\"name\":\"xian\",\"content\":\"西安未来人工智能计算中心\",\"content_en\":\"Xi'an AI Center\"},{\"id\":7,\"pclcci\":\"more\",\"content\":\"鹏城云计算所\",\"content_en\":\"Pengcheng Cloud Computing Institute\"},{\"id\":8,\"name\":\"xuchang\",\"content\":\"中原人工智能计算中心\",\"content_en\":\"Zhongyuan AI Center\"},{\"id\":9,\"name\":\"chengdu\",\"content\":\"成都人工智能计算中心\",\"content_en\":\"Chengdu AI Center\"},{\"id\":10,\"name\":\"more\",\"content\":\"横琴先进智能计算中心\",\"content_en\":\"Hengqin AI Center\"},{\"id\":11,\"name\":\"more\",\"content\":\"国家超级计算济南中心\",\"content_en\":\"HPC & AI Center\"}]}")
Grampus.AiCenterCodeAndNameInfo = sec.Key("AI_CENTER_CODE_AND_NAME").MustString("{\"sequence\":[{\"id\":1,\"name\":\"cloudbrain_one\",\"content\":\"鹏城云脑一号\",\"content_en\":\"Pencheng Cloudbrain Ⅰ\"},{\"id\":2,\"name\":\"cloudbrain_two\",\"content\":\"鹏城云脑二号\",\"content_en\":\"Pencheng Cloudbrain Ⅱ\"},{\"id\":3,\"name\":\"beida\",\"content\":\"北大人工智能集群系统\",\"content_en\":\"Peking University AI Center\"},{\"id\":4,\"name\":\"hefei\",\"content\":\"合肥类脑智能开放平台\",\"content_en\":\"Hefei AI Center\"},{\"id\":5,\"name\":\"wuhan\",\"content\":\"武汉人工智能计算中心\",\"content_en\":\"Wuhan AI Center\"},{\"id\":6,\"name\":\"xian\",\"content\":\"西安未来人工智能计算中心\",\"content_en\":\"Xi'an AI Center\"},{\"id\":7,\"pclcci\":\"more\",\"content\":\"鹏城云计算所\",\"content_en\":\"Pengcheng Cloud Computing Institute\"},{\"id\":8,\"name\":\"xuchang\",\"content\":\"中原人工智能计算中心\",\"content_en\":\"Zhongyuan AI Center\"},{\"id\":9,\"name\":\"chengdu\",\"content\":\"成都人工智能计算中心\",\"content_en\":\"Chengdu AI Center\"},{\"id\":10,\"name\":\"more\",\"content\":\"横琴先进智能计算中心\",\"content_en\":\"Hengqin AI Center\"},{\"id\":11,\"name\":\"more\",\"content\":\"国家超级计算济南中心\",\"content_en\":\"HPC & AI Center\"}]}")
Grampus.UsageRateBeginTime = sec.Key("USAGE_RATE_BEGIN_TIME").MustString("2021-01-01 00:00:00")
if Grampus.C2NetSequence != "" {
if err := json.Unmarshal([]byte(Grampus.C2NetSequence), &C2NetInfos); err != nil {
log.Error("Unmarshal(C2NetSequence) failed:%v", err)
@@ -1689,6 +1694,15 @@ func getGrampusConfig() {
C2NetMapInfo[value.Name] = value
}
}
if Grampus.AiCenterCodeAndNameInfo != "" {
if err := json.Unmarshal([]byte(Grampus.AiCenterCodeAndNameInfo), &C2NetInfos); err != nil {
log.Error("Unmarshal(AiCenterCodeAndNameInfo) failed:%v", err)
}
AiCenterCodeAndNameMapInfo = make(map[string]*C2NetSequenceInfo)
for _, value := range C2NetInfos.C2NetSqInfo {
AiCenterCodeAndNameMapInfo[value.Name] = value
}
}
Grampus.SyncScriptProject = sec.Key("SYNC_SCRIPT_PROJECT").MustString("script_for_grampus")
Grampus.LocalCenterID = sec.Key("LOCAL_CENTER_ID").MustString("cloudbrain2")
Grampus.AiCenterInfo = sec.Key("AI_CENTER_INFO").MustString("")


+ 2
- 2
modules/storage/minio.go View File

@@ -144,8 +144,8 @@ func (m *MinioStorage) HasObject(path string) (bool, error) {

// Indicate to our routine to exit cleanly upon return.
defer close(doneCh)
objectCh := m.client.ListObjects(m.bucket, m.buildMinioPath(path), false, doneCh)
//objectCh := m.client.ListObjects(m.bucket, m.buildMinioPath(path), false, doneCh)
objectCh := m.client.ListObjects(m.bucket, path, false, doneCh)
for object := range objectCh {
if object.Err != nil {
return hasObject, object.Err


+ 26
- 10
modules/storage/minio_ext.go View File

@@ -3,7 +3,6 @@ package storage
import (
"encoding/xml"
"errors"
"path"
"sort"
"strconv"
"strings"
@@ -101,7 +100,7 @@ func getClients() (*minio_ext.Client, *miniov6.Core, error) {
return client, core, nil
}

func GenMultiPartSignedUrl(uuid string, uploadId string, partNumber int, partSize int64) (string, error) {
func GenMultiPartSignedUrl(objectName string, uploadId string, partNumber int, partSize int64) (string, error) {
minioClient, _, err := getClients()
if err != nil {
log.Error("getClients failed:", err.Error())
@@ -110,7 +109,7 @@ func GenMultiPartSignedUrl(uuid string, uploadId string, partNumber int, partSiz

minio := setting.Attachment.Minio
bucketName := minio.Bucket
objectName := strings.TrimPrefix(path.Join(minio.BasePath, path.Join(uuid[0:1], uuid[1:2], uuid)), "/")
//objectName := strings.TrimPrefix(path.Join(minio.BasePath, path.Join(uuid[0:1], uuid[1:2], uuid)), "/")

return minioClient.GenUploadPartSignedUrl(uploadId, bucketName, objectName, partNumber, partSize, PresignedUploadPartUrlExpireTime, setting.Attachment.Minio.Location)
}
@@ -268,6 +267,23 @@ func MinioCopyFiles(bucketName string, srcPath string, destPath string, Files []
return fileTotalSize, nil
}

func MinioCopyAFile(srcBucketName, srcObjectName, destBucketName, destObjectName string) (int64, error) {
_, core, err := getClients()
var fileTotalSize int64
fileTotalSize = 0
if err != nil {
log.Error("getClients failed:", err.Error())
return fileTotalSize, err
}
meta, err := core.StatObject(srcBucketName, srcObjectName, miniov6.StatObjectOptions{})
if err != nil {
log.Info("Get file error:" + err.Error())
}
core.CopyObject(srcBucketName, srcObjectName, destBucketName, destObjectName, meta.UserMetadata)
fileTotalSize = meta.Size
return fileTotalSize, nil
}

func MinioPathCopy(bucketName string, srcPath string, destPath string) (int64, error) {
_, core, err := getClients()
var fileTotalSize int64
@@ -301,7 +317,7 @@ func MinioPathCopy(bucketName string, srcPath string, destPath string) (int64, e
return fileTotalSize, nil
}

func NewMultiPartUpload(uuid string) (string, error) {
func NewMultiPartUpload(objectName string) (string, error) {
_, core, err := getClients()
if err != nil {
log.Error("getClients failed:", err.Error())
@@ -310,12 +326,12 @@ func NewMultiPartUpload(uuid string) (string, error) {

minio := setting.Attachment.Minio
bucketName := minio.Bucket
objectName := strings.TrimPrefix(path.Join(minio.BasePath, path.Join(uuid[0:1], uuid[1:2], uuid)), "/")
//objectName := strings.TrimPrefix(path.Join(minio.BasePath, path.Join(uuid[0:1], uuid[1:2], uuid)), "/")

return core.NewMultipartUpload(bucketName, objectName, miniov6.PutObjectOptions{})
}

func CompleteMultiPartUpload(uuid string, uploadID string, totalChunks int) (string, error) {
func CompleteMultiPartUpload(objectName string, uploadID string, totalChunks int) (string, error) {
client, core, err := getClients()
if err != nil {
log.Error("getClients failed:", err.Error())
@@ -324,8 +340,8 @@ func CompleteMultiPartUpload(uuid string, uploadID string, totalChunks int) (str

minio := setting.Attachment.Minio
bucketName := minio.Bucket
objectName := strings.TrimPrefix(path.Join(minio.BasePath, path.Join(uuid[0:1], uuid[1:2], uuid)), "/")
//objectName := strings.TrimPrefix(path.Join(minio.BasePath, path.Join(uuid[0:1], uuid[1:2], uuid)), "/")
log.Info("bucketName=" + bucketName + " objectName=" + objectName + " uploadID=" + uploadID)
partInfos, err := client.ListObjectParts(bucketName, objectName, uploadID)
if err != nil {
log.Error("ListObjectParts failed:", err.Error())
@@ -351,7 +367,7 @@ func CompleteMultiPartUpload(uuid string, uploadID string, totalChunks int) (str
return core.CompleteMultipartUpload(bucketName, objectName, uploadID, complMultipartUpload.Parts)
}

func GetPartInfos(uuid string, uploadID string) (string, error) {
func GetPartInfos(objectName string, uploadID string) (string, error) {
minioClient, _, err := getClients()
if err != nil {
log.Error("getClients failed:", err.Error())
@@ -360,7 +376,7 @@ func GetPartInfos(uuid string, uploadID string) (string, error) {

minio := setting.Attachment.Minio
bucketName := minio.Bucket
objectName := strings.TrimPrefix(path.Join(minio.BasePath, path.Join(uuid[0:1], uuid[1:2], uuid)), "/")
//objectName := strings.TrimPrefix(path.Join(minio.BasePath, path.Join(uuid[0:1], uuid[1:2], uuid)), "/")

partInfos, err := minioClient.ListObjectParts(bucketName, objectName, uploadID)
if err != nil {


+ 24
- 25
modules/storage/obs.go View File

@@ -90,17 +90,16 @@ func listAllParts(uuid, uploadID, key string) (output *obs.ListPartsOutput, err
} else {
continue
}

break
}

return output, nil
}

func GetObsPartInfos(uuid, uploadID, fileName string) (string, error) {
key := strings.TrimPrefix(path.Join(setting.BasePath, path.Join(uuid[0:1], uuid[1:2], uuid, fileName)), "/")
func GetObsPartInfos(objectName, uploadID string) (string, error) {
key := objectName
//strings.TrimPrefix(path.Join(setting.BasePath, path.Join(uuid[0:1], uuid[1:2], uuid, fileName)), "/")

allParts, err := listAllParts(uuid, uploadID, key)
allParts, err := listAllParts(objectName, uploadID, key)
if err != nil {
log.Error("listAllParts failed: %v", err)
return "", err
@@ -114,10 +113,11 @@ func GetObsPartInfos(uuid, uploadID, fileName string) (string, error) {
return chunks, nil
}

func NewObsMultiPartUpload(uuid, fileName string) (string, error) {
func NewObsMultiPartUpload(objectName string) (string, error) {
input := &obs.InitiateMultipartUploadInput{}
input.Bucket = setting.Bucket
input.Key = strings.TrimPrefix(path.Join(setting.BasePath, path.Join(uuid[0:1], uuid[1:2], uuid, fileName)), "/")
input.Key = objectName
//strings.TrimPrefix(path.Join(setting.BasePath, path.Join(uuid[0:1], uuid[1:2], uuid, fileName)), "/")

output, err := ObsCli.InitiateMultipartUpload(input)
if err != nil {
@@ -128,13 +128,14 @@ func NewObsMultiPartUpload(uuid, fileName string) (string, error) {
return output.UploadId, nil
}

func CompleteObsMultiPartUpload(uuid, uploadID, fileName string, totalChunks int) error {
func CompleteObsMultiPartUpload(objectName, uploadID string, totalChunks int) error {
input := &obs.CompleteMultipartUploadInput{}
input.Bucket = setting.Bucket
input.Key = strings.TrimPrefix(path.Join(setting.BasePath, path.Join(uuid[0:1], uuid[1:2], uuid, fileName)), "/")
//input.Key = strings.TrimPrefix(path.Join(setting.BasePath, path.Join(uuid[0:1], uuid[1:2], uuid, fileName)), "/")
input.Key = objectName
input.UploadId = uploadID

allParts, err := listAllParts(uuid, uploadID, input.Key)
allParts, err := listAllParts(objectName, uploadID, input.Key)
if err != nil {
log.Error("listAllParts failed: %v", err)
return err
@@ -153,15 +154,16 @@ func CompleteObsMultiPartUpload(uuid, uploadID, fileName string, totalChunks int
return err
}

log.Info("uuid:%s, RequestId:%s", uuid, output.RequestId)
log.Info("uuid:%s, RequestId:%s", objectName, output.RequestId)

return nil
}

func ObsMultiPartUpload(uuid string, uploadId string, partNumber int, fileName string, putBody io.ReadCloser) error {
func ObsMultiPartUpload(objectName string, uploadId string, partNumber int, fileName string, putBody io.ReadCloser) error {
input := &obs.UploadPartInput{}
input.Bucket = setting.Bucket
input.Key = strings.TrimPrefix(path.Join(setting.BasePath, path.Join(uuid[0:1], uuid[1:2], uuid, fileName)), "/")
input.Key = objectName
//strings.TrimPrefix(path.Join(setting.BasePath, path.Join(uuid[0:1], uuid[1:2], uuid, fileName)), "/")
input.UploadId = uploadId
input.PartNumber = partNumber
input.Body = putBody
@@ -241,11 +243,6 @@ func ObsDownloadAFile(bucket string, key string) (io.ReadCloser, error) {
}
}

func ObsDownload(uuid string, fileName string) (io.ReadCloser, error) {

return ObsDownloadAFile(setting.Bucket, strings.TrimPrefix(path.Join(setting.BasePath, path.Join(uuid[0:1], uuid[1:2], uuid, fileName)), "/"))
}

func ObsModelDownload(JobName string, fileName string) (io.ReadCloser, error) {
input := &obs.GetObjectInput{}
input.Bucket = setting.Bucket
@@ -297,7 +294,7 @@ func ObsCopyManyFile(srcBucket string, srcPath string, destBucket string, destPa
log.Info("Get File error, error=" + err.Error())
continue
}
obsCopyFile(srcBucket, srcKey, destBucket, destKey)
ObsCopyFile(srcBucket, srcKey, destBucket, destKey)
fileTotalSize += out.ContentLength
}

@@ -321,7 +318,7 @@ func ObsCopyAllFile(srcBucket string, srcPath string, destBucket string, destPat
index++
for _, val := range output.Contents {
destKey := destPath + val.Key[length:]
obsCopyFile(srcBucket, val.Key, destBucket, destKey)
ObsCopyFile(srcBucket, val.Key, destBucket, destKey)
fileTotalSize += val.Size
}
if output.IsTruncated {
@@ -340,7 +337,7 @@ func ObsCopyAllFile(srcBucket string, srcPath string, destBucket string, destPat
return fileTotalSize, nil
}

func obsCopyFile(srcBucket string, srcKeyName string, destBucket string, destKeyName string) error {
func ObsCopyFile(srcBucket string, srcKeyName string, destBucket string, destKeyName string) error {
input := &obs.CopyObjectInput{}
input.Bucket = destBucket
input.Key = destKeyName
@@ -529,11 +526,12 @@ func GetObsListObject(jobName, outPutPath, parentDir, versionName string) ([]Fil
}
}

func ObsGenMultiPartSignedUrl(uuid string, uploadId string, partNumber int, fileName string) (string, error) {
func ObsGenMultiPartSignedUrl(objectName string, uploadId string, partNumber int) (string, error) {

input := &obs.CreateSignedUrlInput{}
input.Bucket = setting.Bucket
input.Key = strings.TrimPrefix(path.Join(setting.BasePath, path.Join(uuid[0:1], uuid[1:2], uuid, fileName)), "/")
input.Key = objectName
//strings.TrimPrefix(path.Join(setting.BasePath, path.Join(uuid[0:1], uuid[1:2], uuid, fileName)), "/")
input.Expires = 60 * 60
input.Method = obs.HttpMethodPut

@@ -581,10 +579,11 @@ func GetObsCreateSignedUrl(jobName, parentDir, fileName string) (string, error)
return GetObsCreateSignedUrlByBucketAndKey(setting.Bucket, strings.TrimPrefix(path.Join(setting.TrainJobModelPath, jobName, setting.OutPutPath, parentDir, fileName), "/"))
}

func ObsGetPreSignedUrl(uuid, fileName string) (string, error) {
func ObsGetPreSignedUrl(objectName, fileName string) (string, error) {
input := &obs.CreateSignedUrlInput{}
input.Method = obs.HttpMethodGet
input.Key = strings.TrimPrefix(path.Join(setting.BasePath, path.Join(uuid[0:1], uuid[1:2], uuid, fileName)), "/")
input.Key = objectName
//strings.TrimPrefix(path.Join(setting.BasePath, path.Join(uuid[0:1], uuid[1:2], uuid, fileName)), "/")
input.Bucket = setting.Bucket
input.Expires = 60 * 60



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

@@ -1273,12 +1273,14 @@ model.manage.model_accuracy = Model Accuracy
model.convert=Model Transformation
model.list=Model List
model.manage.create_new_convert_task=Create Model Transformation Task

model.manage.import_local_model=Import Local Model
model.manage.import_online_model=Import Online Model
model.manage.notcreatemodel=No model has been created
model.manage.init1=Code version: You have not initialized the code repository, please
model.manage.init2=initialized first ;
model.manage.createtrainjob_tip=Training task: you haven't created a training task, please create it first
model.manage.createtrainjob=Training task.
model.manage.createmodel_tip=You can import local model or online model. Import online model should
model.manage.createtrainjob=Create training task.
model.manage.delete=Delete Model
model.manage.delete_confirm=Are you sure to delete this model? Once this model is deleted, it cannot be restored.
model.manage.select.trainjob=Select train task


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

@@ -1287,12 +1287,14 @@ model.manage.model_accuracy = 模型精度
model.convert=模型转换任务
model.list=模型列表
model.manage.create_new_convert_task=创建模型转换任务

model.manage.import_local_model=导入本地模型
model.manage.import_online_model=导入线上模型
model.manage.notcreatemodel=未创建过模型
model.manage.init1=代码版本:您还没有初始化代码仓库,请先
model.manage.init2=创建代码版本;
model.manage.createtrainjob_tip=训练任务:您还没创建过训练任务,请先创建
model.manage.createtrainjob=训练任务。
model.manage.createmodel_tip=您可以导入本地模型或者导入线上模型。导入线上模型需先
model.manage.createtrainjob=创建训练任务。
model.manage.delete=删除模型
model.manage.delete_confirm=你确认删除该模型么?此模型一旦删除不可恢复。
model.manage.select.trainjob=选择训练任务


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

@@ -17,6 +17,7 @@ import (
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
cloudbrainService "code.gitea.io/gitea/services/cloudbrain"
)

const (
@@ -95,6 +96,8 @@ func CloudBrains(ctx *context.Context) {
models.LoadSpecs4CloudbrainInfo(ciTasks)

for i, task := range ciTasks {
ciTasks[i] = cloudbrainService.UpdateCloudbrainAiCenter(ciTasks[i])
ciTasks[i].Cloudbrain.AiCenter = repo.GetAiCenterNameByCode(ciTasks[i].Cloudbrain.AiCenter, ctx.Language())
ciTasks[i].CanDebug = true
ciTasks[i].CanDel = true
ciTasks[i].Cloudbrain.ComputeResource = task.ComputeResource
@@ -186,7 +189,8 @@ func DownloadCloudBrains(ctx *context.Context) {
}
models.LoadSpecs4CloudbrainInfo(pageRecords)
for _, record := range pageRecords {

record = cloudbrainService.UpdateCloudbrainAiCenter(record)
record.Cloudbrain.AiCenter = repo.GetAiCenterNameByCode(record.Cloudbrain.AiCenter, ctx.Language())
for k, v := range allValues(row, record, ctx) {
f.SetCellValue(cloudBrain, k, v)
}
@@ -208,7 +212,7 @@ func allValues(row int, rs *models.CloudbrainInfo, ctx *context.Context) map[str
return map[string]string{getCellName("A", row): rs.DisplayJobName, getCellName("B", row): repo.GetCloudbrainCluster(rs.Cloudbrain, ctx),
getCellName("C", row): rs.JobType, getCellName("D", row): rs.Status, getCellName("E", row): time.Unix(int64(rs.Cloudbrain.CreatedUnix), 0).Format(CREATE_TIME_FORMAT),
getCellName("F", row): getDurationTime(rs), getCellName("G", row): rs.ComputeResource,
getCellName("H", row): repo.GetCloudbrainAiCenter(rs.Cloudbrain, ctx), getCellName("I", row): getCloudbrainCardType(rs),
getCellName("H", row): rs.Cloudbrain.AiCenter, getCellName("I", row): getCloudbrainCardType(rs),
getCellName("J", row): rs.Name, getCellName("K", row): getRepoPathName(rs), getCellName("L", row): rs.JobName,
}
}


+ 21
- 0
routers/admin/resources.go View File

@@ -127,6 +127,7 @@ func GetResourceSpecificationList(ctx *context.Context) {
Status: status,
Cluster: cluster,
AvailableCode: available,
OrderBy: models.SearchSpecOrderById,
})
if err != nil {
log.Error("GetResourceSpecificationList error.%v", err)
@@ -136,6 +137,26 @@ func GetResourceSpecificationList(ctx *context.Context) {
ctx.JSON(http.StatusOK, response.SuccessWithData(list))
}

func GetAllResourceSpecificationList(ctx *context.Context) {
queue := ctx.QueryInt64("queue")
status := ctx.QueryInt("status")
cluster := ctx.Query("cluster")
available := ctx.QueryInt("available")
list, err := resource.GetAllDistinctResourceSpecification(models.SearchResourceSpecificationOptions{
QueueId: queue,
Status: status,
Cluster: cluster,
AvailableCode: available,
})
if err != nil {
log.Error("GetResourceSpecificationList error.%v", err)
ctx.JSON(http.StatusOK, response.ServerError(err.Error()))
return
}

ctx.JSON(http.StatusOK, response.SuccessWithData(list))
}

func GetResourceSpecificationScenes(ctx *context.Context) {
specId := ctx.ParamsInt64(":id")
list, err := resource.GetResourceSpecificationScenes(specId)


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

@@ -631,6 +631,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Get("/overview_resource", repo.GetCloudbrainResourceOverview)
m.Get("/resource_usage_statistic", repo.GetDurationRateStatistic)
m.Get("/resource_usage_rate_detail", repo.GetCloudbrainResourceUsageDetail)
m.Get("/resource_queues", repo.GetResourceQueues)
m.Get("/apitest_for_statistic", repo.CloudbrainDurationStatisticForTest)
})
}, operationReq)
@@ -1017,7 +1018,9 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Get("/query_modelfile_for_predict", repo.QueryModelFileForPredict)
m.Get("/query_train_model", repo.QueryTrainModelList)
m.Post("/create_model_convert", repo.CreateModelConvert)
m.Get("/show_model_convert_page")
m.Get("/show_model_convert_page", repo.ShowModelConvertPage)
m.Get("/query_model_convert_byId", repo.QueryModelConvertById)

m.Get("/:id", repo.GetCloudbrainModelConvertTask)
m.Get("/:id/log", repo.CloudbrainForModelConvertGetLog)
m.Get("/:id/modelartlog", repo.TrainJobForModelConvertGetLog)
@@ -1054,6 +1057,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Get("", repo.GetModelArtsTrainJobVersion)
m.Post("/stop_version", cloudbrain.AdminOrOwnerOrJobCreaterRightForTrain, repo_ext.GrampusStopJob)
m.Get("/log", repo_ext.GrampusGetLog)
m.Get("/metrics", repo_ext.GrampusMetrics)
m.Get("/download_log", cloudbrain.AdminOrJobCreaterRightForTrain, repo_ext.GrampusDownloadLog)
})
})


+ 23
- 3
routers/api/v1/repo/cloudbrain.go View File

@@ -666,12 +666,24 @@ func CloudbrainGetLog(ctx *context.APIContext) {
existStr = taskRes.TaskStatuses[0].ExitDiagnostics
}
ctx.Data["existStr"] = existStr
log.Info("existStr=" + existStr)
} else {
ModelSafetyGetLog(ctx)
return
}
}

if job.JobType == string(models.JobTypeTrain) || job.JobType == string(models.JobTypeInference) {
if job.Type == models.TypeCloudBrainOne {
result, err := cloudbrain.GetJob(job.JobID)
existStr := ""
if err == nil && result != nil {
jobRes, _ := models.ConvertToJobResultPayload(result.Payload)
taskRoles := jobRes.TaskRoles
taskRes, _ := models.ConvertToTaskPod(taskRoles[cloudbrain.SubTaskName].(map[string]interface{}))
existStr = taskRes.TaskStatuses[0].ExitDiagnostics
}
ctx.Data["existStr"] = existStr
}
}

lines := ctx.QueryInt("lines")
@@ -716,17 +728,25 @@ func CloudbrainGetLog(ctx *context.APIContext) {
if result["Content"] != nil {
content = result["Content"].(string)
}

if ctx.Data["existStr"] != nil && result["Lines"].(int) < 50 {
content = content + ctx.Data["existStr"].(string)
}

logFileName := result["FileName"]

//Logs can only be downloaded if the file exists
//and the current user is an administrator or the creator of the task
canLogDownload := logFileName != nil && logFileName != "" && job.IsUserHasRight(ctx.User)

re := map[string]interface{}{
"JobID": ID,
"LogFileName": result["FileName"],
"LogFileName": logFileName,
"StartLine": result["StartLine"],
"EndLine": result["EndLine"],
"Content": content,
"Lines": result["Lines"],
"CanLogDownload": result["FileName"] != "",
"CanLogDownload": canLogDownload,
"StartTime": job.StartTime,
}
//result := CloudbrainGetLogByJobId(job.JobID, job.JobName)


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

@@ -12,6 +12,8 @@ import (
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/routers/repo"
cloudbrainService "code.gitea.io/gitea/services/cloudbrain"
"code.gitea.io/gitea/services/cloudbrain/resource"
"github.com/360EntSecGroup-Skylar/excelize/v2"
)

@@ -121,8 +123,8 @@ func GetOverviewDuration(ctx *context.Context) {
recordBeginTime := recordCloudbrain[0].Cloudbrain.CreatedUnix
now := time.Now()
endTime := now
worker_server_num := 1
cardNum := 1
// worker_server_num := 1
// cardNum := 1
durationAllSum := int64(0)
cardDuSum := int64(0)

@@ -148,34 +150,40 @@ func GetOverviewDuration(ctx *context.Context) {
models.LoadSpecs4CloudbrainInfo(cloudbrains)

for _, cloudbrain := range cloudbrains {
if cloudbrain.Cloudbrain.WorkServerNumber >= 1 {
worker_server_num = cloudbrain.Cloudbrain.WorkServerNumber
} else {
worker_server_num = 1
}
if cloudbrain.Cloudbrain.Spec == nil {
cardNum = 1
} else {
cardNum = cloudbrain.Cloudbrain.Spec.AccCardsNum
}
duration := cloudbrain.Duration
durationSum := cloudbrain.Duration * int64(worker_server_num) * int64(cardNum)
cloudbrain = cloudbrainService.UpdateCloudbrainAiCenter(cloudbrain)
CardDurationString := repo.GetCloudbrainCardDuration(cloudbrain.Cloudbrain)
CardDuration := models.ConvertStrToDuration(CardDurationString)
// if cloudbrain.Cloudbrain.WorkServerNumber >= 1 {
// worker_server_num = cloudbrain.Cloudbrain.WorkServerNumber
// } else {
// worker_server_num = 1
// }
// if cloudbrain.Cloudbrain.Spec == nil {
// cardNum = 1
// } else {
// cardNum = cloudbrain.Cloudbrain.Spec.AccCardsNum
// }
// duration := cloudbrain.Duration
// duration := cloudbrain.Duration
duration := models.ConvertStrToDuration(cloudbrain.TrainJobDuration)
// CardDuration := cloudbrain.Duration * int64(worker_server_num) * int64(cardNum)

if cloudbrain.Cloudbrain.Type == models.TypeCloudBrainOne {
cloudBrainOneDuration += duration
cloudBrainOneCardDuSum += durationSum
cloudBrainOneCardDuSum += CardDuration
} else if cloudbrain.Cloudbrain.Type == models.TypeCloudBrainTwo {
cloudBrainTwoDuration += duration
cloudBrainTwoCardDuSum += durationSum
cloudBrainTwoCardDuSum += CardDuration
} else if cloudbrain.Cloudbrain.Type == models.TypeC2Net {
c2NetDuration += duration
c2NetCardDuSum += durationSum
c2NetCardDuSum += CardDuration
} else if cloudbrain.Cloudbrain.Type == models.TypeCDCenter {
cDCenterDuration += duration
cDNetCardDuSum += durationSum
cDNetCardDuSum += CardDuration
}

durationAllSum += duration
cardDuSum += durationSum
cardDuSum += CardDuration
}
ctx.JSON(http.StatusOK, map[string]interface{}{
"cloudBrainOneCardDuSum": cloudBrainOneCardDuSum,
@@ -192,6 +200,28 @@ func GetOverviewDuration(ctx *context.Context) {
})
}

func GetCloudbrainCardDuration(task models.Cloudbrain) string {
cardNum := int(0)
spec, err := resource.GetCloudbrainSpec(task.ID)
if err != nil {
log.Info("error:" + err.Error())
return ""
}
if spec != nil {
cardNum = spec.AccCardsNum
} else {
cardNum = 1
}
var workServerNumber int64
if task.WorkServerNumber >= 1 {
workServerNumber = int64(task.WorkServerNumber)
} else {
workServerNumber = 1
}
cardDuration := models.ConvertDurationToStr(workServerNumber * int64(cardNum) * task.Duration)
return cardDuration
}

func GetAllCloudbrainsTrend(ctx *context.Context) {

queryType := ctx.QueryTrim("type")
@@ -703,6 +733,30 @@ func GetCloudbrainsDetailData(ctx *context.Context) {
aiCenter := ctx.Query("aiCenter")
needDeleteInfo := ctx.Query("needDeleteInfo")

if cloudBrainType == models.TypeCloudBrainOne && aiCenter == models.AICenterOfCloudBrainOne {
aiCenter = ""
}
if cloudBrainType == models.TypeCloudBrainTwo && aiCenter == models.AICenterOfCloudBrainTwo {
aiCenter = ""
}
if cloudBrainType == models.TypeCDCenter && aiCenter == models.AICenterOfChengdu {
aiCenter = ""
}
if cloudBrainType == models.TypeCloudBrainAll {
if aiCenter == models.AICenterOfCloudBrainOne {
cloudBrainType = models.TypeCloudBrainOne
aiCenter = ""
}
if aiCenter == models.AICenterOfCloudBrainTwo {
cloudBrainType = models.TypeCloudBrainTwo
aiCenter = ""
}
if aiCenter == models.AICenterOfChengdu {
cloudBrainType = models.TypeCDCenter
aiCenter = ""
}
}

page := ctx.QueryInt("page")
pageSize := ctx.QueryInt("pagesize")
if page <= 0 {
@@ -732,7 +786,7 @@ func GetCloudbrainsDetailData(ctx *context.Context) {

keyword := strings.Trim(ctx.Query("q"), " ")

ciTasks, _, err := models.CloudbrainAll(&models.CloudbrainsOptions{
ciTasks, count, err := models.CloudbrainAll(&models.CloudbrainsOptions{
ListOptions: models.ListOptions{
Page: page,
PageSize: pageSize,
@@ -747,8 +801,8 @@ func GetCloudbrainsDetailData(ctx *context.Context) {
NeedRepoInfo: true,
BeginTimeUnix: int64(recordBeginTime),
EndTimeUnix: endTime.Unix(),
// AiCenter: aiCenter,
NeedDeleteInfo: needDeleteInfo,
AiCenter: aiCenter,
NeedDeleteInfo: needDeleteInfo,
})
if err != nil {
ctx.ServerError("Get job failed:", err)
@@ -758,45 +812,43 @@ func GetCloudbrainsDetailData(ctx *context.Context) {
nilTime := time.Time{}
tasks := []models.TaskDetail{}
for i, task := range ciTasks {
if aiCenter == "" || aiCenter == task.Cloudbrain.Spec.AiCenterCode {
ciTasks[i].Cloudbrain.ComputeResource = task.ComputeResource
var taskDetail models.TaskDetail
taskDetail.ID = ciTasks[i].Cloudbrain.ID
taskDetail.JobID = ciTasks[i].Cloudbrain.JobID
taskDetail.JobName = ciTasks[i].JobName
taskDetail.DisplayJobName = ciTasks[i].DisplayJobName
taskDetail.Status = ciTasks[i].Status
taskDetail.JobType = ciTasks[i].JobType
taskDetail.CreatedUnix = ciTasks[i].Cloudbrain.CreatedUnix
taskDetail.RunTime = ciTasks[i].Cloudbrain.TrainJobDuration
taskDetail.StartTime = ciTasks[i].StartTime
taskDetail.EndTime = ciTasks[i].EndTime
taskDetail.ComputeResource = ciTasks[i].ComputeResource
taskDetail.Type = ciTasks[i].Cloudbrain.Type
taskDetail.UserName = ciTasks[i].User.Name
taskDetail.RepoID = ciTasks[i].RepoID
if ciTasks[i].Repo != nil {
taskDetail.RepoName = ciTasks[i].Repo.OwnerName + "/" + ciTasks[i].Repo.Name
taskDetail.RepoAlias = ciTasks[i].Repo.OwnerName + "/" + ciTasks[i].Repo.Alias
}
if ciTasks[i].Cloudbrain.WorkServerNumber >= 1 {
taskDetail.WorkServerNum = int64(ciTasks[i].Cloudbrain.WorkServerNumber)
} else {
taskDetail.WorkServerNum = 1
}
taskDetail.CardDuration = repo.GetCloudbrainCardDuration(ciTasks[i].Cloudbrain)
taskDetail.WaitTime = repo.GetCloudbrainWaitTime(ciTasks[i].Cloudbrain)
task = cloudbrainService.UpdateCloudbrainAiCenter(task)
var taskDetail models.TaskDetail
taskDetail.ID = ciTasks[i].Cloudbrain.ID
taskDetail.JobID = ciTasks[i].Cloudbrain.JobID
taskDetail.JobName = ciTasks[i].JobName
taskDetail.DisplayJobName = ciTasks[i].DisplayJobName
taskDetail.Status = ciTasks[i].Status
taskDetail.JobType = ciTasks[i].JobType
taskDetail.CreatedUnix = ciTasks[i].Cloudbrain.CreatedUnix
taskDetail.RunTime = ciTasks[i].Cloudbrain.TrainJobDuration
taskDetail.StartTime = ciTasks[i].StartTime
taskDetail.EndTime = ciTasks[i].EndTime
taskDetail.ComputeResource = ciTasks[i].ComputeResource
taskDetail.Type = ciTasks[i].Cloudbrain.Type
taskDetail.UserName = ciTasks[i].User.Name
taskDetail.RepoID = ciTasks[i].RepoID
taskDetail.AiCenter = repo.GetAiCenterNameByCode(task.Cloudbrain.AiCenter, ctx.Language())
if ciTasks[i].Repo != nil {
taskDetail.RepoName = ciTasks[i].Repo.OwnerName + "/" + ciTasks[i].Repo.Name
taskDetail.RepoAlias = ciTasks[i].Repo.OwnerName + "/" + ciTasks[i].Repo.Alias
}
if ciTasks[i].Cloudbrain.WorkServerNumber >= 1 {
taskDetail.WorkServerNum = int64(ciTasks[i].Cloudbrain.WorkServerNumber)
} else {
taskDetail.WorkServerNum = 1
}
taskDetail.CardDuration = repo.GetCloudbrainCardDuration(ciTasks[i].Cloudbrain)
taskDetail.WaitTime = repo.GetCloudbrainWaitTime(ciTasks[i].Cloudbrain)

if ciTasks[i].Cloudbrain.DeletedAt != nilTime || ciTasks[i].Repo == nil {
taskDetail.IsDelete = true
} else {
taskDetail.IsDelete = false
}
taskDetail.Spec = ciTasks[i].Spec
tasks = append(tasks, taskDetail)
if ciTasks[i].Cloudbrain.DeletedAt != nilTime || ciTasks[i].Repo == nil {
taskDetail.IsDelete = true
} else {
taskDetail.IsDelete = false
}
taskDetail.Spec = ciTasks[i].Spec
tasks = append(tasks, taskDetail)
}
count := int64(len(tasks))
pager := context.NewPagination(int(count), pageSize, page, getTotalPage(count, pageSize))
pager.SetDefaultParams(ctx)
pager.AddParam(ctx, "listType", "ListType")
@@ -1176,6 +1228,12 @@ func getMonthCloudbrainInfo(beginTime time.Time, endTime time.Time) ([]DateCloud
}

func DownloadCloudBrainBoard(ctx *context.Context) {
recordCloudbrain, err := models.GetRecordBeginTime()
if err != nil {
log.Error("Can not get recordCloudbrain", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err"))
return
}

page := 1

@@ -1184,14 +1242,20 @@ func DownloadCloudBrainBoard(ctx *context.Context) {
var cloudBrain = ctx.Tr("repo.cloudbrain")
fileName := getCloudbrainFileName(cloudBrain)

recordBeginTime := recordCloudbrain[0].Cloudbrain.CreatedUnix
now := time.Now()
endTime := now

_, total, err := models.CloudbrainAll(&models.CloudbrainsOptions{
ListOptions: models.ListOptions{
Page: page,
PageSize: pageSize,
},
Type: models.TypeCloudBrainAll,
NeedRepoInfo: false,
Type: models.TypeCloudBrainAll,
BeginTimeUnix: int64(recordBeginTime),
EndTimeUnix: endTime.Unix(),
})
log.Info("totalcountisis:", total)

if err != nil {
log.Warn("Can not get cloud brain info", err)
@@ -1216,8 +1280,10 @@ func DownloadCloudBrainBoard(ctx *context.Context) {
Page: page,
PageSize: pageSize,
},
Type: models.TypeCloudBrainAll,
NeedRepoInfo: true,
Type: models.TypeCloudBrainAll,
BeginTimeUnix: int64(recordBeginTime),
EndTimeUnix: endTime.Unix(),
NeedRepoInfo: true,
})
if err != nil {
log.Warn("Can not get cloud brain info", err)
@@ -1225,7 +1291,8 @@ func DownloadCloudBrainBoard(ctx *context.Context) {
}
models.LoadSpecs4CloudbrainInfo(pageRecords)
for _, record := range pageRecords {

record = cloudbrainService.UpdateCloudbrainAiCenter(record)
record.Cloudbrain.AiCenter = repo.GetAiCenterNameByCode(record.Cloudbrain.AiCenter, ctx.Language())
for k, v := range allCloudbrainValues(row, record, ctx) {
f.SetCellValue(cloudBrain, k, v)
}
@@ -1264,7 +1331,7 @@ func allCloudbrainValues(row int, rs *models.CloudbrainInfo, ctx *context.Contex
getCellName("G", row): rs.TrainJobDuration, getCellName("H", row): repo.GetCloudbrainCardDuration(rs.Cloudbrain),
getCellName("I", row): getBrainStartTime(rs),
getCellName("J", row): getBrainEndTime(rs), getCellName("K", row): rs.ComputeResource, getCellName("L", row): getCloudbrainCardType(rs),
getCellName("M", row): getWorkServerNum(rs), getCellName("N", row): repo.GetCloudbrainAiCenter(rs.Cloudbrain, ctx),
getCellName("M", row): getWorkServerNum(rs), getCellName("N", row): rs.Cloudbrain.AiCenter,
getCellName("O", row): getCloudbrainFlavorName(rs), getCellName("P", row): rs.Name,
getCellName("Q", row): getBrainRepo(rs), getCellName("R", row): rs.JobName, getCellName("S", row): getBrainDeleteTime(rs),
}
@@ -1417,7 +1484,7 @@ func GetCloudbrainResourceOverview(ctx *context.Context) {
log.Error("Can not get GetDurationRecordBeginTime", err)
return
}
recordBeginTime := recordCloudbrainDuration[0].CreatedUnix
recordBeginTime := recordCloudbrainDuration[0].DateTime
recordUpdateTime := time.Now().Unix()
resourceQueues, err := models.GetCanUseCardInfo()
if err != nil {
@@ -1428,11 +1495,12 @@ func GetCloudbrainResourceOverview(ctx *context.Context) {
C2NetResourceDetail := []models.ResourceDetail{}
for _, resourceQueue := range resourceQueues {
if resourceQueue.Cluster == models.OpenICluster {
aiCenterName := repo.GetAiCenterNameByCode(resourceQueue.AiCenterCode, ctx.Language())
var resourceDetail models.ResourceDetail
resourceDetail.QueueCode = resourceQueue.QueueCode
resourceDetail.Cluster = resourceQueue.Cluster
resourceDetail.AiCenterCode = resourceQueue.AiCenterCode
resourceDetail.AiCenterName = resourceQueue.AiCenterName + "/" + resourceQueue.AiCenterCode
resourceDetail.AiCenterName = resourceQueue.AiCenterCode + "/" + aiCenterName
resourceDetail.ComputeResource = resourceQueue.ComputeResource
resourceDetail.AccCardType = resourceQueue.AccCardType + "(" + resourceQueue.ComputeResource + ")"
resourceDetail.CardsTotalNum = resourceQueue.CardsTotalNum
@@ -1440,11 +1508,12 @@ func GetCloudbrainResourceOverview(ctx *context.Context) {
OpenIResourceDetail = append(OpenIResourceDetail, resourceDetail)
}
if resourceQueue.Cluster == models.C2NetCluster {
aiCenterName := repo.GetAiCenterNameByCode(resourceQueue.AiCenterCode, ctx.Language())
var resourceDetail models.ResourceDetail
resourceDetail.QueueCode = resourceQueue.QueueCode
resourceDetail.Cluster = resourceQueue.Cluster
resourceDetail.AiCenterCode = resourceQueue.AiCenterCode
resourceDetail.AiCenterName = resourceQueue.AiCenterName + "/" + resourceQueue.AiCenterCode
resourceDetail.AiCenterName = resourceQueue.AiCenterCode + "/" + aiCenterName
resourceDetail.ComputeResource = resourceQueue.ComputeResource
resourceDetail.AccCardType = resourceQueue.AccCardType + "(" + resourceQueue.ComputeResource + ")"
resourceDetail.CardsTotalNum = resourceQueue.CardsTotalNum
@@ -1554,7 +1623,7 @@ func getBeginAndEndTime(ctx *context.Context) (time.Time, time.Time) {
ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err"))
return beginTime, endTime
}
brainRecordBeginTime := recordCloudbrainDuration[0].CreatedUnix.AsTime()
brainRecordBeginTime := recordCloudbrainDuration[0].DateTime.AsTime()
beginTime = brainRecordBeginTime
endTime = now
} else if queryType == "today" {
@@ -1596,7 +1665,7 @@ func getBeginAndEndTime(ctx *context.Context) (time.Time, time.Time) {
ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err"))
return beginTime, endTime
}
brainRecordBeginTime := recordCloudbrainDuration[0].CreatedUnix.AsTime()
brainRecordBeginTime := recordCloudbrainDuration[0].DateTime.AsTime()
beginTime = brainRecordBeginTime
endTime = now
} else {
@@ -1627,7 +1696,7 @@ func getAiCenterUsageDuration(beginTime time.Time, endTime time.Time, cloudbrain
usageRate := float64(0)

for _, cloudbrainStatistic := range cloudbrainStatistics {
if int64(cloudbrainStatistic.CreatedUnix) >= beginTime.Unix() && int64(cloudbrainStatistic.CreatedUnix) < endTime.Unix() {
if int64(cloudbrainStatistic.DateTime) >= beginTime.Unix() && int64(cloudbrainStatistic.DateTime) < endTime.Unix() {
totalDuration += cloudbrainStatistic.CardsTotalDuration
usageDuration += cloudbrainStatistic.CardsUseDuration
}
@@ -1659,28 +1728,29 @@ func getDurationStatistic(beginTime time.Time, endTime time.Time) (models.Durati
return OpenIDurationRate, C2NetDurationRate, 0
}
for _, cloudbrainStatistic := range cardDurationStatistics {
aiCenterName := cloudbrainStatistic.AiCenterCode + "/" + repo.GetAiCenterNameByCode(cloudbrainStatistic.AiCenterCode, "zh-CN")
if cloudbrainStatistic.Cluster == models.OpenICluster {
if _, ok := OpenITotalDuration[cloudbrainStatistic.AiCenterName]; !ok {
OpenITotalDuration[cloudbrainStatistic.AiCenterName] = cloudbrainStatistic.CardsTotalDuration
if _, ok := OpenITotalDuration[aiCenterName]; !ok {
OpenITotalDuration[aiCenterName] = cloudbrainStatistic.CardsTotalDuration
} else {
OpenITotalDuration[cloudbrainStatistic.AiCenterName] += cloudbrainStatistic.CardsTotalDuration
OpenITotalDuration[aiCenterName] += cloudbrainStatistic.CardsTotalDuration
}
if _, ok := OpenIUsageDuration[cloudbrainStatistic.AiCenterName]; !ok {
OpenIUsageDuration[cloudbrainStatistic.AiCenterName] = cloudbrainStatistic.CardsUseDuration
if _, ok := OpenIUsageDuration[aiCenterName]; !ok {
OpenIUsageDuration[aiCenterName] = cloudbrainStatistic.CardsUseDuration
} else {
OpenIUsageDuration[cloudbrainStatistic.AiCenterName] += cloudbrainStatistic.CardsUseDuration
OpenIUsageDuration[aiCenterName] += cloudbrainStatistic.CardsUseDuration
}
}
if cloudbrainStatistic.Cluster == models.C2NetCluster {
if _, ok := C2NetTotalDuration[cloudbrainStatistic.AiCenterName]; !ok {
C2NetTotalDuration[cloudbrainStatistic.AiCenterName] = cloudbrainStatistic.CardsTotalDuration
if _, ok := C2NetTotalDuration[aiCenterName]; !ok {
C2NetTotalDuration[aiCenterName] = cloudbrainStatistic.CardsTotalDuration
} else {
C2NetTotalDuration[cloudbrainStatistic.AiCenterName] += cloudbrainStatistic.CardsTotalDuration
C2NetTotalDuration[aiCenterName] += cloudbrainStatistic.CardsTotalDuration
}
if _, ok := C2NetUsageDuration[cloudbrainStatistic.AiCenterName]; !ok {
C2NetUsageDuration[cloudbrainStatistic.AiCenterName] = cloudbrainStatistic.CardsUseDuration
if _, ok := C2NetUsageDuration[aiCenterName]; !ok {
C2NetUsageDuration[aiCenterName] = cloudbrainStatistic.CardsUseDuration
} else {
C2NetUsageDuration[cloudbrainStatistic.AiCenterName] += cloudbrainStatistic.CardsUseDuration
C2NetUsageDuration[aiCenterName] += cloudbrainStatistic.CardsUseDuration
}
}
}
@@ -1690,16 +1760,17 @@ func getDurationStatistic(beginTime time.Time, endTime time.Time) (models.Durati
return OpenIDurationRate, C2NetDurationRate, 0
}
for _, v := range ResourceAiCenterRes {
aiCenterName := v.AiCenterCode + "/" + repo.GetAiCenterNameByCode(v.AiCenterCode, "zh-CN")
if cutString(v.AiCenterCode, 4) == cutString(models.AICenterOfCloudBrainOne, 4) {
if _, ok := OpenIUsageDuration[v.AiCenterName]; !ok {
OpenIUsageDuration[v.AiCenterName] = 0
if _, ok := OpenIUsageDuration[aiCenterName]; !ok {
OpenIUsageDuration[aiCenterName] = 0
}
if _, ok := OpenITotalDuration[v.AiCenterName]; !ok {
OpenITotalDuration[v.AiCenterName] = 0
if _, ok := OpenITotalDuration[aiCenterName]; !ok {
OpenITotalDuration[aiCenterName] = 0
}
} else {
if _, ok := C2NetUsageDuration[v.AiCenterName]; !ok {
C2NetUsageDuration[v.AiCenterName] = 0
if _, ok := C2NetUsageDuration[aiCenterName]; !ok {
C2NetUsageDuration[aiCenterName] = 0
}
}
}
@@ -1716,7 +1787,7 @@ func getDurationStatistic(beginTime time.Time, endTime time.Time) (models.Durati
for _, v := range OpenITotalDuration {
totalCanUse += float64(v)
}
for _, v := range OpenIUsageRate {
for _, v := range OpenIUsageDuration {
totalUse += float64(v)
}
if totalCanUse == 0 || totalUse == 0 {
@@ -1724,6 +1795,7 @@ func getDurationStatistic(beginTime time.Time, endTime time.Time) (models.Durati
} else {
totalUsageRate = totalUse / totalCanUse
}
delete(C2NetUsageDuration, "/")

OpenIDurationRate.AiCenterTotalDurationStat = OpenITotalDuration
OpenIDurationRate.AiCenterUsageDurationStat = OpenIUsageDuration
@@ -1831,3 +1903,30 @@ func getHourCloudbrainDuration(beginTime time.Time, endTime time.Time, aiCenterC
hourTimeStatistic.HourTimeUsageRate = hourTimeUsageRate
return hourTimeStatistic, nil
}

func CloudbrainUpdateAiCenter(ctx *context.Context) {
repo.CloudbrainDurationStatisticHour()
ctx.JSON(http.StatusOK, map[string]interface{}{
"message": 0,
})
}

func GetResourceQueues(ctx *context.Context) {
resourceQueues, err := models.GetCanUseCardInfo()
if err != nil {
log.Info("GetCanUseCardInfo err: %v", err)
return
}
Resource := make([]*models.ResourceQueue, 0)
aiCenterCodeMap := make(map[string]string)
for _, resourceQueue := range resourceQueues {
if _, ok := aiCenterCodeMap[resourceQueue.AiCenterCode]; !ok {
resourceQueue.AiCenterName = repo.GetAiCenterNameByCode(resourceQueue.AiCenterCode, ctx.Language())
aiCenterCodeMap[resourceQueue.AiCenterCode] = resourceQueue.AiCenterCode
Resource = append(Resource, resourceQueue)
}
}
ctx.JSON(http.StatusOK, map[string]interface{}{
"resourceQueues": Resource,
})
}

+ 13
- 11
routers/api/v1/repo/modelarts.go View File

@@ -150,7 +150,6 @@ func GetModelArtsTrainJobVersion(ctx *context.APIContext) {
if len(result.JobInfo.Tasks) > 0 {
if len(result.JobInfo.Tasks[0].CenterID) > 0 && len(result.JobInfo.Tasks[0].CenterName) > 0 {
job.AiCenter = result.JobInfo.Tasks[0].CenterID[0] + "+" + result.JobInfo.Tasks[0].CenterName[0]
// aiCenterName = result.JobInfo.Tasks[0].CenterName[0]
aiCenterName = cloudbrainService.GetAiCenterShow(job.AiCenter, ctx.Context)
}
}
@@ -285,15 +284,6 @@ func TrainJobGetLog(ctx *context.APIContext) {
return
}

prefix := strings.TrimPrefix(path.Join(setting.TrainJobModelPath, task.JobName, modelarts.LogPath, versionName), "/") + "/job"
_, err = storage.GetObsLogFileName(prefix)
var canLogDownload bool
if err != nil {
canLogDownload = false
} else {
canLogDownload = true
}

ctx.Data["log_file_name"] = resultLogFile.LogFileList[0]

ctx.JSON(http.StatusOK, map[string]interface{}{
@@ -303,11 +293,23 @@ func TrainJobGetLog(ctx *context.APIContext) {
"EndLine": result.EndLine,
"Content": result.Content,
"Lines": result.Lines,
"CanLogDownload": canLogDownload,
"CanLogDownload": canLogDownload(ctx.User, task),
"StartTime": task.StartTime,
})
}

func canLogDownload(user *models.User, task *models.Cloudbrain) bool {
if task == nil || !task.IsUserHasRight(user) {
return false
}
prefix := strings.TrimPrefix(path.Join(setting.TrainJobModelPath, task.JobName, modelarts.LogPath, task.VersionName), "/") + "/job"
_, err := storage.GetObsLogFileName(prefix)
if err != nil {
return false
}
return true
}

func trainJobGetLogContent(jobID string, versionID int64, baseLine string, order string, lines int) (*models.GetTrainJobLogFileNamesResult, *models.GetTrainJobLogResult, error) {

resultLogFile, err := modelarts.GetTrainJobLogFileNames(jobID, strconv.FormatInt(versionID, 10))


+ 9
- 0
routers/api/v1/repo/modelmanage.go View File

@@ -104,3 +104,12 @@ func ShowModelConvertPage(ctx *context.APIContext) {
}

}

func QueryModelConvertById(ctx *context.APIContext) {
modelResult, err := routerRepo.GetModelConvertById(ctx.Context)
if err == nil {
ctx.JSON(http.StatusOK, modelResult)
} else {
ctx.JSON(http.StatusOK, nil)
}
}

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

@@ -6,9 +6,10 @@
package private

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

"code.gitea.io/gitea/routers/admin"

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

"code.gitea.io/gitea/modules/log"
@@ -52,7 +53,9 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Get("/tool/org_stat", OrgStatisticManually)
m.Post("/tool/update_repo_visit/:date", UpdateRepoVisit)
m.Post("/task/history_handle/duration", repo.HandleTaskWithNoDuration)
m.Post("/task/history_handle/aicenter", repo.HandleTaskWithAiCenter)
m.Post("/resources/specification/handle_historical_task", admin.RefreshHistorySpec)
m.Post("/duration_statisctic/history_handle", repo.CloudbrainUpdateHistoryData)

}, CheckInternalToken)
}

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

@@ -150,6 +150,7 @@ func SaveModelConvert(ctx *context.Context) {
go goCreateTask(modelConvert, ctx, task)

ctx.JSON(200, map[string]string{
"id": id,
"code": "0",
})
}
@@ -726,6 +727,11 @@ func ShowModelConvertPageInfo(ctx *context.Context) {
}
}

func GetModelConvertById(ctx *context.Context) (*models.AiModelConvert, error) {
id := ctx.Query("id")
return models.QueryModelConvertById(id)
}

func GetModelConvertPageData(ctx *context.Context) ([]*models.AiModelConvert, int64, error) {
page := ctx.QueryInt("page")
if page <= 0 {


+ 291
- 32
routers/repo/ai_model_manage.go View File

@@ -22,16 +22,24 @@ import (
)

const (
Model_prefix = "aimodels/"
tplModelManageIndex = "repo/modelmanage/index"
tplModelManageDownload = "repo/modelmanage/download"
tplModelInfo = "repo/modelmanage/showinfo"
MODEL_LATEST = 1
MODEL_NOT_LATEST = 0
MODEL_MAX_SIZE = 1024 * 1024 * 1024
STATUS_COPY_MODEL = 1
STATUS_FINISHED = 0
STATUS_ERROR = 2
Attachment_model = "model"
Model_prefix = "aimodels/"
tplModelManageIndex = "repo/modelmanage/index"
tplModelManageDownload = "repo/modelmanage/download"
tplModelInfo = "repo/modelmanage/showinfo"
tplCreateLocalModelInfo = "repo/modelmanage/create_local_1"
tplCreateLocalForUploadModelInfo = "repo/modelmanage/create_local_2"
tplCreateOnlineModelInfo = "repo/modelmanage/create_online"

MODEL_LATEST = 1
MODEL_NOT_LATEST = 0
MODEL_MAX_SIZE = 1024 * 1024 * 1024
STATUS_COPY_MODEL = 1
STATUS_FINISHED = 0
STATUS_ERROR = 2

MODEL_LOCAL_TYPE = 1
MODEL_ONLINE_TYPE = 0
)

func saveModelByParameters(jobId string, versionName string, name string, version string, label string, description string, engine int, ctx *context.Context) (string, error) {
@@ -70,13 +78,12 @@ func saveModelByParameters(jobId string, versionName string, name string, versio
cloudType = models.TypeCloudBrainTwo
} else if aiTask.ComputeResource == models.GPUResource {
cloudType = models.TypeCloudBrainOne
spec, err := resource.GetCloudbrainSpec(aiTask.ID)
if err == nil {
flaverName := "GPU: " + fmt.Sprint(spec.AccCardsNum) + "*" + spec.AccCardType + ",CPU: " + fmt.Sprint(spec.CpuCores) + "," + ctx.Tr("cloudbrain.memory") + ": " + fmt.Sprint(spec.MemGiB) + "GB," + ctx.Tr("cloudbrain.shared_memory") + ": " + fmt.Sprint(spec.ShareMemGiB) + "GB"
aiTask.FlavorName = flaverName
}
}

spec, err := resource.GetCloudbrainSpec(aiTask.ID)
if err == nil {
specJson, _ := json.Marshal(spec)
aiTask.FlavorName = string(specJson)
}
accuracy := make(map[string]string)
accuracy["F1"] = ""
accuracy["Recall"] = ""
@@ -189,6 +196,139 @@ func SaveNewNameModel(ctx *context.Context) {
log.Info("save model end.")
}

func SaveLocalModel(ctx *context.Context) {
if !ctx.Repo.CanWrite(models.UnitTypeModelManage) {
ctx.Error(403, ctx.Tr("repo.model_noright"))
return
}
re := map[string]string{
"code": "-1",
}
log.Info("save SaveLocalModel start.")
uuid := uuid.NewV4()
id := uuid.String()
name := ctx.Query("name")
version := ctx.Query("version")
if version == "" {
version = "0.0.1"
}
label := ctx.Query("label")
description := ctx.Query("description")
engine := ctx.QueryInt("engine")
taskType := ctx.QueryInt("type")
modelActualPath := ""
if taskType == models.TypeCloudBrainOne {
destKeyNamePrefix := Model_prefix + models.AttachmentRelativePath(id) + "/"
modelActualPath = setting.Attachment.Minio.Bucket + "/" + destKeyNamePrefix
} else if taskType == models.TypeCloudBrainTwo {
destKeyNamePrefix := Model_prefix + models.AttachmentRelativePath(id) + "/"
modelActualPath = setting.Bucket + "/" + destKeyNamePrefix
} else {
re["msg"] = "type is error."
ctx.JSON(200, re)
return
}
var lastNewModelId string
repoId := ctx.Repo.Repository.ID
aimodels := models.QueryModelByName(name, repoId)
if len(aimodels) > 0 {
for _, model := range aimodels {
if model.Version == version {
re["msg"] = ctx.Tr("repo.model.manage.create_error")
ctx.JSON(200, re)
return
}
if model.New == MODEL_LATEST {
lastNewModelId = model.ID
}
}
}
model := &models.AiModelManage{
ID: id,
Version: version,
ModelType: MODEL_LOCAL_TYPE,
VersionCount: len(aimodels) + 1,
Label: label,
Name: name,
Description: description,
New: MODEL_LATEST,
Type: taskType,
Path: modelActualPath,
Size: 0,
AttachmentId: "",
RepoId: repoId,
UserId: ctx.User.ID,
Engine: int64(engine),
TrainTaskInfo: "",
Accuracy: "",
Status: STATUS_FINISHED,
}

err := models.SaveModelToDb(model)
if err != nil {
re["msg"] = err.Error()
ctx.JSON(200, re)
return
}
if len(lastNewModelId) > 0 {
//udpate status and version count
models.ModifyModelNewProperty(lastNewModelId, MODEL_NOT_LATEST, 0)
}
var units []models.RepoUnit
var deleteUnitTypes []models.UnitType
units = append(units, models.RepoUnit{
RepoID: ctx.Repo.Repository.ID,
Type: models.UnitTypeModelManage,
Config: &models.ModelManageConfig{
EnableModelManage: true,
},
})
deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeModelManage)

models.UpdateRepositoryUnits(ctx.Repo.Repository, units, deleteUnitTypes)

log.Info("save model end.")
notification.NotifyOtherTask(ctx.User, ctx.Repo.Repository, id, name, models.ActionCreateNewModelTask)
re["code"] = "0"
re["id"] = id
ctx.JSON(200, re)
}

func getSize(files []storage.FileInfo) int64 {
var size int64
for _, file := range files {
size += file.Size
}
return size
}

func UpdateModelSize(modeluuid string) {
model, err := models.QueryModelById(modeluuid)
if err == nil {
if model.Type == models.TypeCloudBrainOne {
if strings.HasPrefix(model.Path, setting.Attachment.Minio.Bucket+"/"+Model_prefix) {
files, err := storage.GetAllObjectByBucketAndPrefixMinio(setting.Attachment.Minio.Bucket, model.Path[len(setting.Attachment.Minio.Bucket)+1:])
if err != nil {
log.Info("Failed to query model size from minio. id=" + modeluuid)
}
size := getSize(files)
models.ModifyModelSize(modeluuid, size)
}
} else if model.Type == models.TypeCloudBrainTwo {
if strings.HasPrefix(model.Path, setting.Bucket+"/"+Model_prefix) {
files, err := storage.GetAllObjectByBucketAndPrefix(setting.Bucket, model.Path[len(setting.Bucket)+1:])
if err != nil {
log.Info("Failed to query model size from obs. id=" + modeluuid)
}
size := getSize(files)
models.ModifyModelSize(modeluuid, size)
}
}
} else {
log.Info("not found model,uuid=" + modeluuid)
}
}

func SaveModel(ctx *context.Context) {
if !ctx.Repo.CanWrite(models.UnitTypeModelManage) {
ctx.Error(403, ctx.Tr("repo.model_noright"))
@@ -292,6 +432,60 @@ func downloadModelFromCloudBrainOne(modelUUID string, jobName string, parentDir
return "", 0, nil
}
}
func DeleteModelFile(ctx *context.Context) {
log.Info("delete model start.")
id := ctx.Query("id")
fileName := ctx.Query("fileName")
model, err := models.QueryModelById(id)
if err == nil {
if model.ModelType == MODEL_LOCAL_TYPE {
if model.Type == models.TypeCloudBrainOne {
bucketName := setting.Attachment.Minio.Bucket
objectName := model.Path[len(bucketName)+1:] + fileName
log.Info("delete bucket=" + bucketName + " path=" + objectName)
if strings.HasPrefix(model.Path, bucketName+"/"+Model_prefix) {
totalSize := storage.MinioGetFilesSize(bucketName, []string{objectName})
err := storage.Attachments.DeleteDir(objectName)
if err != nil {
log.Info("Failed to delete model. id=" + id)
re := map[string]string{
"code": "-1",
}
re["msg"] = err.Error()
ctx.JSON(200, re)
return
} else {
log.Info("delete minio file size is:" + fmt.Sprint(totalSize))
models.ModifyModelSize(id, model.Size-totalSize)
}
}
} else if model.Type == models.TypeCloudBrainTwo {
bucketName := setting.Bucket
objectName := model.Path[len(setting.Bucket)+1:] + fileName
log.Info("delete bucket=" + setting.Bucket + " path=" + objectName)
if strings.HasPrefix(model.Path, bucketName+"/"+Model_prefix) {
totalSize := storage.ObsGetFilesSize(bucketName, []string{objectName})
err := storage.ObsRemoveObject(bucketName, objectName)
if err != nil {
log.Info("Failed to delete model. id=" + id)
re := map[string]string{
"code": "-1",
}
re["msg"] = err.Error()
ctx.JSON(200, re)
return
} else {
log.Info("delete obs file size is:" + fmt.Sprint(totalSize))
models.ModifyModelSize(id, model.Size-totalSize)
}
}
}
}
}
ctx.JSON(200, map[string]string{
"code": "0",
})
}

func DeleteModel(ctx *context.Context) {
log.Info("delete model start.")
@@ -317,14 +511,28 @@ func deleteModelByID(ctx *context.Context, id string) error {
return errors.New(ctx.Tr("repo.model_noright"))
}
if err == nil {
log.Info("bucket=" + setting.Bucket + " path=" + model.Path)
if strings.HasPrefix(model.Path, setting.Bucket+"/"+Model_prefix) {
err := storage.ObsRemoveObject(setting.Bucket, model.Path[len(setting.Bucket)+1:])
if err != nil {
log.Info("Failed to delete model. id=" + id)
return err

if model.Type == models.TypeCloudBrainOne {
bucketName := setting.Attachment.Minio.Bucket
log.Info("bucket=" + bucketName + " path=" + model.Path)
if strings.HasPrefix(model.Path, bucketName+"/"+Model_prefix) {
err := storage.Attachments.DeleteDir(model.Path[len(bucketName)+1:])
if err != nil {
log.Info("Failed to delete model. id=" + id)
return err
}
}
} else if model.Type == models.TypeCloudBrainTwo {
log.Info("bucket=" + setting.Bucket + " path=" + model.Path)
if strings.HasPrefix(model.Path, setting.Bucket+"/"+Model_prefix) {
err := storage.ObsRemoveObject(setting.Bucket, model.Path[len(setting.Bucket)+1:])
if err != nil {
log.Info("Failed to delete model. id=" + id)
return err
}
}
}

err = models.DeleteModelById(id)
if err == nil { //find a model to change new
aimodels := models.QueryModelByName(model.Name, model.RepoId)
@@ -884,29 +1092,58 @@ func ModifyModel(id string, description string) error {
func ModifyModelInfo(ctx *context.Context) {
log.Info("modify model start.")
id := ctx.Query("id")
description := ctx.Query("description")

re := map[string]string{
"code": "-1",
}
task, err := models.QueryModelById(id)
if err != nil {
re["msg"] = err.Error()
log.Error("no such model!", err.Error())
ctx.ServerError("no such model:", err)
ctx.JSON(200, re)
return
}
if !isOper(ctx, task.UserId) {
ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
//ctx.ServerError("no right.", errors.New(ctx.Tr("repo.model_noright")))
re["msg"] = "No right to operation."
ctx.JSON(200, re)
return
}
if task.ModelType == MODEL_LOCAL_TYPE {
name := ctx.Query("name")
label := ctx.Query("label")
description := ctx.Query("description")
engine := ctx.QueryInt("engine")
aimodels := models.QueryModelByName(name, task.RepoId)
if aimodels != nil && len(aimodels) > 0 {
if len(aimodels) == 1 {
if aimodels[0].ID != task.ID {
re["msg"] = ctx.Tr("repo.model.manage.create_error")
ctx.JSON(200, re)
return
}
} else {
re["msg"] = ctx.Tr("repo.model.manage.create_error")
ctx.JSON(200, re)
return
}
}
err = models.ModifyLocalModel(id, name, label, description, engine)

err = ModifyModel(id, description)
} else {
label := ctx.Query("label")
description := ctx.Query("description")
engine := task.Engine
name := task.Name
err = models.ModifyLocalModel(id, name, label, description, int(engine))
}

if err != nil {
log.Info("modify error," + err.Error())
ctx.ServerError("error.", err)
re["msg"] = err.Error()
ctx.JSON(200, re)
return
} else {
ctx.JSON(200, "success")
re["code"] = "0"
ctx.JSON(200, re)
}

}

func QueryModelListForPredict(ctx *context.Context) {
@@ -1004,3 +1241,25 @@ func QueryOneLevelModelFile(ctx *context.Context) {
ctx.JSON(http.StatusOK, fileinfos)
}
}

func CreateLocalModel(ctx *context.Context) {
ctx.Data["isModelManage"] = true
ctx.Data["ModelManageAccess"] = ctx.Repo.CanWrite(models.UnitTypeModelManage)

ctx.HTML(200, tplCreateLocalModelInfo)
}

func CreateLocalModelForUpload(ctx *context.Context) {
ctx.Data["uuid"] = ctx.Query("uuid")
ctx.Data["isModelManage"] = true
ctx.Data["ModelManageAccess"] = ctx.Repo.CanWrite(models.UnitTypeModelManage)
ctx.Data["max_model_size"] = setting.MaxModelSize * MODEL_MAX_SIZE
ctx.HTML(200, tplCreateLocalForUploadModelInfo)
}

func CreateOnlineModel(ctx *context.Context) {
ctx.Data["isModelManage"] = true
ctx.Data["ModelManageAccess"] = ctx.Repo.CanWrite(models.UnitTypeModelManage)

ctx.HTML(200, tplCreateOnlineModelInfo)
}

+ 18
- 17
routers/repo/attachment.go View File

@@ -11,6 +11,7 @@ import (
"fmt"
"mime/multipart"
"net/http"
"path"
"strconv"
"strings"

@@ -311,7 +312,8 @@ func GetAttachment(ctx *context.Context) {
url = setting.PROXYURL + "/obs_proxy_download?uuid=" + attach.UUID + "&file_name=" + attach.Name
log.Info("return url=" + url)
} else {
url, err = storage.ObsGetPreSignedUrl(attach.UUID, attach.Name)
objectName := strings.TrimPrefix(path.Join(setting.BasePath, path.Join(attach.UUID[0:1], attach.UUID[1:2], attach.UUID, attach.Name)), "/")
url, err = storage.ObsGetPreSignedUrl(objectName, attach.Name)
if err != nil {
ctx.ServerError("ObsGetPreSignedUrl", err)
return
@@ -415,7 +417,7 @@ func AddAttachment(ctx *context.Context) {
uuid := ctx.Query("uuid")
has := false
if typeCloudBrain == models.TypeCloudBrainOne {
has, err = storage.Attachments.HasObject(models.AttachmentRelativePath(uuid))
has, err = storage.Attachments.HasObject(setting.Attachment.Minio.BasePath + models.AttachmentRelativePath(uuid))
if err != nil {
ctx.ServerError("HasObject", err)
return
@@ -557,7 +559,7 @@ func GetSuccessChunks(ctx *context.Context) {

isExist := false
if typeCloudBrain == models.TypeCloudBrainOne {
isExist, err = storage.Attachments.HasObject(models.AttachmentRelativePath(fileChunk.UUID))
isExist, err = storage.Attachments.HasObject(setting.Attachment.Minio.BasePath + models.AttachmentRelativePath(fileChunk.UUID))
if err != nil {
ctx.ServerError("HasObject failed", err)
return
@@ -593,12 +595,12 @@ func GetSuccessChunks(ctx *context.Context) {
}

if typeCloudBrain == models.TypeCloudBrainOne {
chunks, err = storage.GetPartInfos(fileChunk.UUID, fileChunk.UploadID)
chunks, err = storage.GetPartInfos(strings.TrimPrefix(path.Join(setting.Attachment.Minio.BasePath, path.Join(fileChunk.UUID[0:1], fileChunk.UUID[1:2], fileChunk.UUID)), "/"), fileChunk.UploadID)
if err != nil {
log.Error("GetPartInfos failed:%v", err.Error())
}
} else {
chunks, err = storage.GetObsPartInfos(fileChunk.UUID, fileChunk.UploadID, fileName)
chunks, err = storage.GetObsPartInfos(strings.TrimPrefix(path.Join(setting.BasePath, path.Join(fileChunk.UUID[0:1], fileChunk.UUID[1:2], fileChunk.UUID, fileName)), "/"), fileChunk.UploadID)
if err != nil {
log.Error("GetObsPartInfos failed:%v", err.Error())
}
@@ -699,13 +701,13 @@ func NewMultipart(ctx *context.Context) {
uuid := gouuid.NewV4().String()
var uploadID string
if typeCloudBrain == models.TypeCloudBrainOne {
uploadID, err = storage.NewMultiPartUpload(uuid)
uploadID, err = storage.NewMultiPartUpload(strings.TrimPrefix(path.Join(setting.Attachment.Minio.BasePath, path.Join(uuid[0:1], uuid[1:2], uuid)), "/"))
if err != nil {
ctx.ServerError("NewMultipart", err)
return
}
} else {
uploadID, err = storage.NewObsMultiPartUpload(uuid, fileName)
uploadID, err = storage.NewObsMultiPartUpload(strings.TrimPrefix(path.Join(setting.BasePath, path.Join(uuid[0:1], uuid[1:2], uuid, fileName)), "/"))
if err != nil {
ctx.ServerError("NewObsMultiPartUpload", err)
return
@@ -749,8 +751,8 @@ func PutOBSProxyUpload(ctx *context.Context) {
ctx.Error(500, fmt.Sprintf("FormFile: %v", RequestBody))
return
}
err := storage.ObsMultiPartUpload(uuid, uploadID, partNumber, fileName, RequestBody.ReadCloser())
objectName := strings.TrimPrefix(path.Join(setting.BasePath, path.Join(uuid[0:1], uuid[1:2], uuid, fileName)), "/")
err := storage.ObsMultiPartUpload(objectName, uploadID, partNumber, fileName, RequestBody.ReadCloser())
if err != nil {
log.Info("upload error.")
}
@@ -759,8 +761,8 @@ func PutOBSProxyUpload(ctx *context.Context) {
func GetOBSProxyDownload(ctx *context.Context) {
uuid := ctx.Query("uuid")
fileName := ctx.Query("file_name")
body, err := storage.ObsDownload(uuid, fileName)
objectName := strings.TrimPrefix(path.Join(setting.BasePath, path.Join(uuid[0:1], uuid[1:2], uuid, fileName)), "/")
body, err := storage.ObsDownloadAFile(setting.Bucket, objectName)
if err != nil {
log.Info("upload error.")
} else {
@@ -805,7 +807,7 @@ func GetMultipartUploadUrl(ctx *context.Context) {
return
}

url, err = storage.GenMultiPartSignedUrl(uuid, uploadID, partNumber, size)
url, err = storage.GenMultiPartSignedUrl(strings.TrimPrefix(path.Join(setting.Attachment.Minio.BasePath, path.Join(uuid[0:1], uuid[1:2], uuid)), "/"), uploadID, partNumber, size)
if err != nil {
ctx.Error(500, fmt.Sprintf("GenMultiPartSignedUrl failed: %v", err))
return
@@ -815,7 +817,7 @@ func GetMultipartUploadUrl(ctx *context.Context) {
url = setting.PROXYURL + "/obs_proxy_multipart?uuid=" + uuid + "&uploadId=" + uploadID + "&partNumber=" + fmt.Sprint(partNumber) + "&file_name=" + fileName
log.Info("return url=" + url)
} else {
url, err = storage.ObsGenMultiPartSignedUrl(uuid, uploadID, partNumber, fileName)
url, err = storage.ObsGenMultiPartSignedUrl(strings.TrimPrefix(path.Join(setting.BasePath, path.Join(uuid[0:1], uuid[1:2], uuid, fileName)), "/"), uploadID, partNumber)
if err != nil {
ctx.Error(500, fmt.Sprintf("ObsGenMultiPartSignedUrl failed: %v", err))
return
@@ -823,7 +825,6 @@ func GetMultipartUploadUrl(ctx *context.Context) {
log.Info("url=" + url)
}
}

ctx.JSON(200, map[string]string{
"url": url,
})
@@ -855,13 +856,13 @@ func CompleteMultipart(ctx *context.Context) {
}

if typeCloudBrain == models.TypeCloudBrainOne {
_, err = storage.CompleteMultiPartUpload(uuid, uploadID, fileChunk.TotalChunks)
_, err = storage.CompleteMultiPartUpload(strings.TrimPrefix(path.Join(setting.Attachment.Minio.BasePath, path.Join(fileChunk.UUID[0:1], fileChunk.UUID[1:2], fileChunk.UUID)), "/"), uploadID, fileChunk.TotalChunks)
if err != nil {
ctx.Error(500, fmt.Sprintf("CompleteMultiPartUpload failed: %v", err))
return
}
} else {
err = storage.CompleteObsMultiPartUpload(uuid, uploadID, fileName, fileChunk.TotalChunks)
err = storage.CompleteObsMultiPartUpload(strings.TrimPrefix(path.Join(setting.BasePath, path.Join(fileChunk.UUID[0:1], fileChunk.UUID[1:2], fileChunk.UUID, fileName)), "/"), uploadID, fileChunk.TotalChunks)
if err != nil {
ctx.Error(500, fmt.Sprintf("CompleteObsMultiPartUpload failed: %v", err))
return
@@ -1013,7 +1014,7 @@ func queryDatasets(ctx *context.Context, attachs []*models.AttachmentUsername) {
}

for _, attch := range attachs {
has, err := storage.Attachments.HasObject(models.AttachmentRelativePath(attch.UUID))
has, err := storage.Attachments.HasObject(setting.Attachment.Minio.BasePath + models.AttachmentRelativePath(attch.UUID))
if err != nil || !has {
continue
}


+ 323
- 0
routers/repo/attachment_model.go View File

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

import (
"fmt"
"path"
"strconv"
"strings"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/minio_ext"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/storage"
"code.gitea.io/gitea/modules/upload"
gouuid "github.com/satori/go.uuid"
)

func GetModelChunks(ctx *context.Context) {
fileMD5 := ctx.Query("md5")
typeCloudBrain := ctx.QueryInt("type")
fileName := ctx.Query("file_name")
scene := ctx.Query("scene")
modeluuid := ctx.Query("modeluuid")
log.Info("scene=" + scene + " typeCloudBrain=" + fmt.Sprint(typeCloudBrain))
var chunks string

err := checkTypeCloudBrain(typeCloudBrain)
if err != nil {
ctx.ServerError("checkTypeCloudBrain failed", err)
return
}

fileChunk, err := models.GetModelFileChunkByMD5AndUser(fileMD5, ctx.User.ID, typeCloudBrain, modeluuid)
if err != nil {
if models.IsErrFileChunkNotExist(err) {
ctx.JSON(200, map[string]string{
"uuid": "",
"uploaded": "0",
"uploadID": "",
"chunks": "",
})
} else {
ctx.ServerError("GetFileChunkByMD5", err)
}
return
}

isExist := false
if typeCloudBrain == models.TypeCloudBrainOne {
isExist, err = storage.Attachments.HasObject(fileChunk.ObjectName)
if isExist {
log.Info("The file is exist in minio. has uploaded.path=" + fileChunk.ObjectName)
} else {
log.Info("The file is not exist in minio..")
}
if err != nil {
ctx.ServerError("HasObject failed", err)
return
}
} else {
isExist, err = storage.ObsHasObject(fileChunk.ObjectName)
if isExist {
log.Info("The file is exist in obs. has uploaded. path=" + fileChunk.ObjectName)
} else {
log.Info("The file is not exist in obs.")
}
if err != nil {
ctx.ServerError("ObsHasObject failed", err)
return
}
}

if isExist {
if fileChunk.IsUploaded == models.FileNotUploaded {
log.Info("the file has been uploaded but not recorded")
fileChunk.IsUploaded = models.FileUploaded
if err = models.UpdateModelFileChunk(fileChunk); err != nil {
log.Error("UpdateFileChunk failed:", err.Error())
}
}
modelname := ""
model, err := models.QueryModelById(modeluuid)
if err == nil && model != nil {
modelname = model.Name
}
ctx.JSON(200, map[string]string{
"uuid": fileChunk.UUID,
"uploaded": strconv.Itoa(fileChunk.IsUploaded),
"uploadID": fileChunk.UploadID,
"chunks": string(chunks),
"attachID": "0",
"modeluuid": modeluuid,
"fileName": fileName,
"modelName": modelname,
})
} else {
if fileChunk.IsUploaded == models.FileUploaded {
log.Info("the file has been recorded but not uploaded")
fileChunk.IsUploaded = models.FileNotUploaded
if err = models.UpdateModelFileChunk(fileChunk); err != nil {
log.Error("UpdateFileChunk failed:", err.Error())
}
}

if typeCloudBrain == models.TypeCloudBrainOne {
chunks, err = storage.GetPartInfos(fileChunk.ObjectName, fileChunk.UploadID)
if err != nil {
log.Error("GetPartInfos failed:%v", err.Error())
}
} else {
chunks, err = storage.GetObsPartInfos(fileChunk.ObjectName, fileChunk.UploadID)
if err != nil {
log.Error("GetObsPartInfos failed:%v", err.Error())
}
}
if err != nil {
models.DeleteModelFileChunk(fileChunk)
ctx.JSON(200, map[string]string{
"uuid": "",
"uploaded": "0",
"uploadID": "",
"chunks": "",
})
} else {
ctx.JSON(200, map[string]string{
"uuid": fileChunk.UUID,
"uploaded": strconv.Itoa(fileChunk.IsUploaded),
"uploadID": fileChunk.UploadID,
"chunks": string(chunks),
"attachID": "0",
"datasetID": "0",
"fileName": "",
"datasetName": "",
})
}
}
}

func getObjectName(filename string, modeluuid string) string {
return strings.TrimPrefix(path.Join(Model_prefix, path.Join(modeluuid[0:1], modeluuid[1:2], modeluuid, filename)), "/")
}

func NewModelMultipart(ctx *context.Context) {
if !setting.Attachment.Enabled {
ctx.Error(404, "attachment is not enabled")
return
}
fileName := ctx.Query("file_name")
modeluuid := ctx.Query("modeluuid")

err := upload.VerifyFileType(ctx.Query("fileType"), strings.Split(setting.Attachment.AllowedTypes, ","))
if err != nil {
ctx.Error(400, err.Error())
return
}

typeCloudBrain := ctx.QueryInt("type")
err = checkTypeCloudBrain(typeCloudBrain)
if err != nil {
ctx.ServerError("checkTypeCloudBrain failed", err)
return
}

if setting.Attachment.StoreType == storage.MinioStorageType {
totalChunkCounts := ctx.QueryInt("totalChunkCounts")
if totalChunkCounts > minio_ext.MaxPartsCount {
ctx.Error(400, fmt.Sprintf("chunk counts(%d) is too much", totalChunkCounts))
return
}

fileSize := ctx.QueryInt64("size")
if fileSize > minio_ext.MaxMultipartPutObjectSize {
ctx.Error(400, fmt.Sprintf("file size(%d) is too big", fileSize))
return
}

uuid := gouuid.NewV4().String()
var uploadID string
var objectName string
if typeCloudBrain == models.TypeCloudBrainOne {
objectName = strings.TrimPrefix(path.Join(Model_prefix, path.Join(modeluuid[0:1], modeluuid[1:2], modeluuid, fileName)), "/")
uploadID, err = storage.NewMultiPartUpload(objectName)
if err != nil {
ctx.ServerError("NewMultipart", err)
return
}
} else {

objectName = strings.TrimPrefix(path.Join(Model_prefix, path.Join(modeluuid[0:1], modeluuid[1:2], modeluuid, fileName)), "/")
uploadID, err = storage.NewObsMultiPartUpload(objectName)
if err != nil {
ctx.ServerError("NewObsMultiPartUpload", err)
return
}
}

_, err = models.InsertModelFileChunk(&models.ModelFileChunk{
UUID: uuid,
UserID: ctx.User.ID,
UploadID: uploadID,
Md5: ctx.Query("md5"),
Size: fileSize,
ObjectName: objectName,
ModelUUID: modeluuid,
TotalChunks: totalChunkCounts,
Type: typeCloudBrain,
})

if err != nil {
ctx.Error(500, fmt.Sprintf("InsertFileChunk: %v", err))
return
}

ctx.JSON(200, map[string]string{
"uuid": uuid,
"uploadID": uploadID,
})
} else {
ctx.Error(404, "storage type is not enabled")
return
}
}

func GetModelMultipartUploadUrl(ctx *context.Context) {
uuid := ctx.Query("uuid")
uploadID := ctx.Query("uploadID")
partNumber := ctx.QueryInt("chunkNumber")
size := ctx.QueryInt64("size")
typeCloudBrain := ctx.QueryInt("type")
err := checkTypeCloudBrain(typeCloudBrain)
if err != nil {
ctx.ServerError("checkTypeCloudBrain failed", err)
return
}
fileChunk, err := models.GetModelFileChunkByUUID(uuid)
if err != nil {
if models.IsErrFileChunkNotExist(err) {
ctx.Error(404)
} else {
ctx.ServerError("GetFileChunkByUUID", err)
}
return
}
url := ""
if typeCloudBrain == models.TypeCloudBrainOne {
if size > minio_ext.MinPartSize {
ctx.Error(400, fmt.Sprintf("chunk size(%d) is too big", size))
return
}
url, err = storage.GenMultiPartSignedUrl(fileChunk.ObjectName, uploadID, partNumber, size)
if err != nil {
ctx.Error(500, fmt.Sprintf("GenMultiPartSignedUrl failed: %v", err))
return
}
} else {
url, err = storage.ObsGenMultiPartSignedUrl(fileChunk.ObjectName, uploadID, partNumber)
if err != nil {
ctx.Error(500, fmt.Sprintf("ObsGenMultiPartSignedUrl failed: %v", err))
return
}
log.Info("url=" + url)

}

ctx.JSON(200, map[string]string{
"url": url,
})
}

func CompleteModelMultipart(ctx *context.Context) {
uuid := ctx.Query("uuid")
uploadID := ctx.Query("uploadID")
typeCloudBrain := ctx.QueryInt("type")
modeluuid := ctx.Query("modeluuid")
log.Warn("uuid:" + uuid)
log.Warn("modeluuid:" + modeluuid)
log.Warn("typeCloudBrain:" + strconv.Itoa(typeCloudBrain))

err := checkTypeCloudBrain(typeCloudBrain)
if err != nil {
ctx.ServerError("checkTypeCloudBrain failed", err)
return
}
fileChunk, err := models.GetModelFileChunkByUUID(uuid)
if err != nil {
if models.IsErrFileChunkNotExist(err) {
ctx.Error(404)
} else {
ctx.ServerError("GetFileChunkByUUID", err)
}
return
}

if typeCloudBrain == models.TypeCloudBrainOne {
_, err = storage.CompleteMultiPartUpload(fileChunk.ObjectName, uploadID, fileChunk.TotalChunks)
if err != nil {
ctx.Error(500, fmt.Sprintf("CompleteMultiPartUpload failed: %v", err))
return
}
} else {
err = storage.CompleteObsMultiPartUpload(fileChunk.ObjectName, uploadID, fileChunk.TotalChunks)
if err != nil {
ctx.Error(500, fmt.Sprintf("CompleteObsMultiPartUpload failed: %v", err))
return
}
}

fileChunk.IsUploaded = models.FileUploaded

err = models.UpdateModelFileChunk(fileChunk)
if err != nil {
ctx.Error(500, fmt.Sprintf("UpdateFileChunk: %v", err))
return
}
//更新模型大小信息
UpdateModelSize(modeluuid)

ctx.JSON(200, map[string]string{
"result_code": "0",
})

}

+ 157
- 65
routers/repo/cloudbrain_statistic.go View File

@@ -1,38 +1,87 @@
package repo

import (
"net/http"
"strings"
"time"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/timeutil"
cloudbrainService "code.gitea.io/gitea/services/cloudbrain"
)

func CloudbrainDurationStatisticHour() {

dateTime := time.Now().Format("2006-01-02 15:04:05")
dayTime := time.Now().Format("2006-01-02")
var statisticTime time.Time
var count int64
recordDurationUpdateTime, err := models.GetDurationRecordUpdateTime()
if err != nil {
log.Error("Can not get GetDurationRecordBeginTime", err)
}
now := time.Now()

currentTime := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, now.Location())
if err == nil && len(recordDurationUpdateTime) > 0 {
statisticTime = time.Unix(int64(recordDurationUpdateTime[0].DateTime), 0).Add(+1 * time.Hour)
} else {
statisticTime = currentTime
}
deleteBeginTime := time.Unix(int64(recordDurationUpdateTime[0].DateTime), 0)

err = models.DeleteCloudbrainDurationStatistic(timeutil.TimeStamp(deleteBeginTime.Unix()), timeutil.TimeStamp(currentTime.Unix()))
if err != nil {
log.Error("DeleteCloudbrainDurationStatistic failed", err)
}

for statisticTime.Before(currentTime) || statisticTime.Equal(currentTime) {
countEach := summaryDurationStat(statisticTime)
count += countEach
statisticTime = statisticTime.Add(+1 * time.Hour)
}
log.Info("summaryDurationStat count: %v", count)
}
func UpdateDurationStatisticHistoryData(beginTime time.Time, endTime time.Time) int64 {
var count int64
statisticTime := beginTime
currentTime := endTime
for statisticTime.Before(currentTime) || statisticTime.Equal(currentTime) {
countEach := summaryDurationStat(statisticTime)
count += countEach
statisticTime = statisticTime.Add(+1 * time.Hour)
}
return count
}

m, _ := time.ParseDuration("-1h")
beginTime := currentTime.Add(m).Unix()
endTime := currentTime.Unix()
hourTime := currentTime.Add(m).Hour()
//statisticTime是当前的时辰,比如当前是2019-01-01 12:01:01,那么statisticTime就是2019-01-01 12:00:00
func summaryDurationStat(statisticTime time.Time) int64 {
var count int64
dateTime := timeutil.TimeStamp(statisticTime.Add(-1 * time.Hour).Unix())
beginTime := statisticTime.Add(-1 * time.Hour).Unix()
dayTime := statisticTime.Add(-1 * time.Hour).Format("2006-01-02")
hourTime := statisticTime.Add(-1 * time.Hour).Hour()
endTime := statisticTime.Unix()

ciTasks, err := models.GetCloudbrainByTime(beginTime, endTime)
if err != nil {
log.Info("GetCloudbrainByTime err: %v", err)
return
return 0
}
specMap := make(map[string]*models.Specification)
cloudbrainMap := make(map[string]*models.Cloudbrain)
models.LoadSpecs4CloudbrainInfo(ciTasks)

for _, cloudbrain := range ciTasks {
if _, ok := specMap[cloudbrain.Cloudbrain.Spec.AiCenterCode+"/"+cloudbrain.Cloudbrain.Spec.AccCardType]; !ok {
if cloudbrain.Cloudbrain.Spec != nil {
specMap[cloudbrain.Cloudbrain.Spec.AiCenterCode+"/"+cloudbrain.Cloudbrain.Spec.AccCardType] = cloudbrain.Cloudbrain.Spec
if cloudbrain.Cloudbrain.StartTime == 0 {
cloudbrain.Cloudbrain.StartTime = cloudbrain.Cloudbrain.CreatedUnix
}
if cloudbrain.Cloudbrain.EndTime == 0 {
cloudbrain.Cloudbrain.EndTime = cloudbrain.Cloudbrain.UpdatedUnix
}
cloudbrain = cloudbrainService.UpdateCloudbrainAiCenter(cloudbrain)
if cloudbrain.Cloudbrain.Spec != nil {
if _, ok := cloudbrainMap[cloudbrain.Cloudbrain.AiCenter+"/"+cloudbrain.Cloudbrain.Spec.AccCardType]; !ok {
if cloudbrain.Cloudbrain.Spec != nil {
cloudbrainMap[cloudbrain.Cloudbrain.AiCenter+"/"+cloudbrain.Cloudbrain.Spec.AccCardType] = &cloudbrain.Cloudbrain
}
}
}
}
@@ -42,69 +91,83 @@ func CloudbrainDurationStatisticHour() {
resourceQueues, err := models.GetCanUseCardInfo()
if err != nil {
log.Info("GetCanUseCardInfo err: %v", err)
return
return 0
}

cardsTotalDurationMap := make(map[string]int)
for _, resourceQueue := range resourceQueues {
cardsTotalDurationMap[resourceQueue.Cluster+"/"+resourceQueue.AiCenterName+"/"+resourceQueue.AiCenterCode+"/"+resourceQueue.AccCardType+"/"+resourceQueue.ComputeResource] = resourceQueue.CardsTotalNum * 1 * 60 * 60
if _, ok := cardsTotalDurationMap[resourceQueue.Cluster+"/"+resourceQueue.AiCenterCode+"/"+resourceQueue.AccCardType]; !ok {
cardsTotalDurationMap[resourceQueue.Cluster+"/"+resourceQueue.AiCenterCode+"/"+resourceQueue.AccCardType] = resourceQueue.CardsTotalNum * 1 * 60 * 60
} else {
cardsTotalDurationMap[resourceQueue.Cluster+"/"+resourceQueue.AiCenterCode+"/"+resourceQueue.AccCardType] += resourceQueue.CardsTotalNum * 1 * 60 * 60
}
}

for centerCode, CardTypeInfo := range cloudBrainCenterCodeAndCardTypeInfo {
for cardType, cardDuration := range CardTypeInfo {
spec := specMap[centerCode+"/"+cardType]
if spec != nil {
if err := models.DeleteCloudbrainDurationStatisticHour(dayTime, hourTime, centerCode, cardType); err != nil {
log.Error("DeleteCloudbrainDurationStatisticHour failed: %v", err.Error())
return
}
if _, ok := cardsTotalDurationMap[spec.Cluster+"/"+spec.AiCenterName+"/"+centerCode+"/"+cardType+"/"+spec.ComputeResource]; !ok {
cardsTotalDurationMap[spec.Cluster+"/"+spec.AiCenterName+"/"+centerCode+"/"+cardType+"/"+spec.ComputeResource] = 0
for centerCode, CardTypes := range cloudBrainCenterCodeAndCardTypeInfo {
for cardType, cardDuration := range CardTypes {
cloudbrainTable := cloudbrainMap[centerCode+"/"+cardType]
if cloudbrainTable != nil {
if _, ok := cardsTotalDurationMap[cloudbrainTable.Cluster+"/"+centerCode+"/"+cardType]; !ok {
cardsTotalDurationMap[cloudbrainTable.Cluster+"/"+centerCode+"/"+cardType] = 0
}
cloudbrainDurationStat := models.CloudbrainDurationStatistic{
DateTime: dateTime,
DayTime: dayTime,
HourTime: hourTime,
Cluster: spec.Cluster,
AiCenterName: spec.AiCenterName,
Cluster: cloudbrainTable.Cluster,
AiCenterName: GetAiCenterNameByCode(centerCode, "zh-CN"),
AiCenterCode: centerCode,
AccCardType: cardType,
ComputeResource: spec.ComputeResource,
CardsUseDuration: cardDuration,
CardsTotalDuration: cardsTotalDurationMap[spec.Cluster+"/"+spec.AiCenterName+"/"+centerCode+"/"+cardType+"/"+spec.ComputeResource],
CardsTotalDuration: cardsTotalDurationMap[cloudbrainTable.Cluster+"/"+centerCode+"/"+cardType],
CreatedUnix: timeutil.TimeStampNow(),
}
if _, err = models.InsertCloudbrainDurationStatistic(&cloudbrainDurationStat); err != nil {
log.Error("Insert cloudbrainDurationStat failed: %v", err.Error())
}
delete(cardsTotalDurationMap, spec.Cluster+"/"+spec.AiCenterName+"/"+centerCode+"/"+cardType+"/"+spec.ComputeResource)
count++
delete(cardsTotalDurationMap, cloudbrainTable.Cluster+"/"+centerCode+"/"+cardType)
}
}
}

for key, cardsTotalDuration := range cardsTotalDurationMap {
if err := models.DeleteCloudbrainDurationStatisticHour(dayTime, hourTime, strings.Split(key, "/")[2], strings.Split(key, "/")[3]); err != nil {
log.Error("DeleteCloudbrainDurationStatisticHour failed: %v", err.Error())
return
}
cloudbrainDurationStat := models.CloudbrainDurationStatistic{
DateTime: dateTime,
DayTime: dayTime,
HourTime: hourTime,
Cluster: strings.Split(key, "/")[0],
AiCenterName: strings.Split(key, "/")[1],
AiCenterCode: strings.Split(key, "/")[2],
AccCardType: strings.Split(key, "/")[3],
ComputeResource: strings.Split(key, "/")[4],
AiCenterName: GetAiCenterNameByCode(strings.Split(key, "/")[1], "zh-CN"),
AiCenterCode: strings.Split(key, "/")[1],
AccCardType: strings.Split(key, "/")[2],
CardsUseDuration: 0,
CardsTotalDuration: cardsTotalDuration,
CardsTotalNum: cardsTotalDuration / 1 / 60 / 60,
CreatedUnix: timeutil.TimeStampNow(),
}
if _, err = models.InsertCloudbrainDurationStatistic(&cloudbrainDurationStat); err != nil {
log.Error("Insert cloudbrainDurationStat failed: %v", err.Error())
}
count++
}

log.Info("finish summary cloudbrainDurationStat")
return count
}

func GetAiCenterNameByCode(centerCode string, language string) string {
var aiCenterName string
aiCenterInfo := cloudbrainService.GetAiCenterInfoByCenterCode(centerCode)
if aiCenterInfo != nil {
if language == "zh-CN" {
aiCenterName = aiCenterInfo.Content
} else {
aiCenterName = aiCenterInfo.ContentEN
}
} else {
aiCenterName = centerCode
}
return aiCenterName
}

func getcloudBrainCenterCodeAndCardTypeInfo(ciTasks []*models.CloudbrainInfo, beginTime int64, endTime int64) map[string]map[string]int {
@@ -112,7 +175,7 @@ func getcloudBrainCenterCodeAndCardTypeInfo(ciTasks []*models.CloudbrainInfo, be
var AccCardsNum int
cloudBrainCenterCodeAndCardType := make(map[string]map[string]int)
for _, cloudbrain := range ciTasks {
cloudbrain = cloudbrainService.UpdateCloudbrainAiCenter(cloudbrain)
if cloudbrain.Cloudbrain.StartTime == 0 {
cloudbrain.Cloudbrain.StartTime = cloudbrain.Cloudbrain.CreatedUnix
}
@@ -129,41 +192,70 @@ func getcloudBrainCenterCodeAndCardTypeInfo(ciTasks []*models.CloudbrainInfo, be
} else {
AccCardsNum = cloudbrain.Cloudbrain.Spec.AccCardsNum
}
if _, ok := cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.Spec.AiCenterCode]; !ok {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.Spec.AiCenterCode] = make(map[string]int)
if _, ok := cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.AiCenter]; !ok {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.AiCenter] = make(map[string]int)
}

if cloudbrain.Cloudbrain.Status == string(models.ModelArtsRunning) {
if _, ok := cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.Spec.AiCenterCode][cloudbrain.Cloudbrain.Spec.AccCardType]; !ok {
if int64(cloudbrain.Cloudbrain.StartTime) < beginTime {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.Spec.AiCenterCode][cloudbrain.Cloudbrain.Spec.AccCardType] = AccCardsNum * WorkServerNumber * (int(endTime) - int(beginTime))
if cloudbrain.Cloudbrain.Spec != nil {
if cloudbrain.Cloudbrain.Status == string(models.ModelArtsRunning) {
if _, ok := cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.AiCenter][cloudbrain.Cloudbrain.Spec.AccCardType]; !ok {
if int64(cloudbrain.Cloudbrain.StartTime) < beginTime {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.AiCenter][cloudbrain.Cloudbrain.Spec.AccCardType] = AccCardsNum * WorkServerNumber * (int(endTime) - int(beginTime))
} else if beginTime <= int64(cloudbrain.Cloudbrain.StartTime) && int64(cloudbrain.Cloudbrain.StartTime) < endTime {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.AiCenter][cloudbrain.Cloudbrain.Spec.AccCardType] = AccCardsNum * WorkServerNumber * (int(endTime) - int(cloudbrain.Cloudbrain.StartTime))
} else if int64(cloudbrain.Cloudbrain.StartTime) >= endTime {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.AiCenter][cloudbrain.Cloudbrain.Spec.AccCardType] = 0
}
} else {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.Spec.AiCenterCode][cloudbrain.Cloudbrain.Spec.AccCardType] = AccCardsNum * WorkServerNumber * (int(endTime) - int(cloudbrain.Cloudbrain.StartTime))
if int64(cloudbrain.Cloudbrain.StartTime) < beginTime {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.AiCenter][cloudbrain.Cloudbrain.Spec.AccCardType] += AccCardsNum * WorkServerNumber * (int(endTime) - int(beginTime))
} else if beginTime <= int64(cloudbrain.Cloudbrain.StartTime) && int64(cloudbrain.Cloudbrain.StartTime) < endTime {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.AiCenter][cloudbrain.Cloudbrain.Spec.AccCardType] += AccCardsNum * WorkServerNumber * (int(endTime) - int(cloudbrain.Cloudbrain.StartTime))
} else if int64(cloudbrain.Cloudbrain.StartTime) >= endTime {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.AiCenter][cloudbrain.Cloudbrain.Spec.AccCardType] += 0
}
}
} else {
if int64(cloudbrain.Cloudbrain.StartTime) < beginTime {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.Spec.AiCenterCode][cloudbrain.Cloudbrain.Spec.AccCardType] += AccCardsNum * WorkServerNumber * (int(endTime) - int(beginTime))
if _, ok := cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.AiCenter][cloudbrain.Cloudbrain.Spec.AccCardType]; !ok {
if int64(cloudbrain.Cloudbrain.StartTime) <= beginTime && int64(cloudbrain.Cloudbrain.EndTime) <= endTime {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.AiCenter][cloudbrain.Cloudbrain.Spec.AccCardType] = AccCardsNum * WorkServerNumber * (int(cloudbrain.Cloudbrain.EndTime) - int(beginTime))
} else if int64(cloudbrain.Cloudbrain.StartTime) <= beginTime && int64(cloudbrain.Cloudbrain.EndTime) > endTime {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.AiCenter][cloudbrain.Cloudbrain.Spec.AccCardType] = AccCardsNum * WorkServerNumber * (int(endTime) - int(beginTime))
} else if beginTime <= int64(cloudbrain.Cloudbrain.StartTime) && int64(cloudbrain.Cloudbrain.StartTime) <= endTime && int64(cloudbrain.Cloudbrain.EndTime) <= endTime {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.AiCenter][cloudbrain.Cloudbrain.Spec.AccCardType] = AccCardsNum * WorkServerNumber * (int(cloudbrain.Cloudbrain.EndTime) - int(cloudbrain.Cloudbrain.StartTime))
} else if beginTime <= int64(cloudbrain.Cloudbrain.StartTime) && int64(cloudbrain.Cloudbrain.StartTime) <= endTime && int64(cloudbrain.Cloudbrain.EndTime) > endTime {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.AiCenter][cloudbrain.Cloudbrain.Spec.AccCardType] = AccCardsNum * WorkServerNumber * (int(endTime) - int(cloudbrain.Cloudbrain.StartTime))
}
} else {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.Spec.AiCenterCode][cloudbrain.Cloudbrain.Spec.AccCardType] += AccCardsNum * WorkServerNumber * (int(endTime) - int(cloudbrain.Cloudbrain.StartTime))
if int64(cloudbrain.Cloudbrain.StartTime) <= beginTime && int64(cloudbrain.Cloudbrain.EndTime) <= endTime {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.AiCenter][cloudbrain.Cloudbrain.Spec.AccCardType] += AccCardsNum * WorkServerNumber * (int(cloudbrain.Cloudbrain.EndTime) - int(beginTime))
} else if int64(cloudbrain.Cloudbrain.StartTime) <= beginTime && int64(cloudbrain.Cloudbrain.EndTime) > endTime {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.AiCenter][cloudbrain.Cloudbrain.Spec.AccCardType] += AccCardsNum * WorkServerNumber * (int(endTime) - int(beginTime))
} else if beginTime <= int64(cloudbrain.Cloudbrain.StartTime) && int64(cloudbrain.Cloudbrain.StartTime) <= endTime && int64(cloudbrain.Cloudbrain.EndTime) <= endTime {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.AiCenter][cloudbrain.Cloudbrain.Spec.AccCardType] += AccCardsNum * WorkServerNumber * (int(cloudbrain.Cloudbrain.EndTime) - int(cloudbrain.Cloudbrain.StartTime))
} else if beginTime <= int64(cloudbrain.Cloudbrain.StartTime) && int64(cloudbrain.Cloudbrain.StartTime) <= endTime && int64(cloudbrain.Cloudbrain.EndTime) > endTime {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.AiCenter][cloudbrain.Cloudbrain.Spec.AccCardType] += AccCardsNum * WorkServerNumber * (int(endTime) - int(cloudbrain.Cloudbrain.StartTime))
}
}
}
} else {
if _, ok := cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.Spec.AiCenterCode][cloudbrain.Cloudbrain.Spec.AccCardType]; !ok {
if int64(cloudbrain.Cloudbrain.StartTime) < beginTime {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.Spec.AiCenterCode][cloudbrain.Cloudbrain.Spec.AccCardType] = AccCardsNum * WorkServerNumber * (int(cloudbrain.Cloudbrain.EndTime) - int(beginTime))
} else {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.Spec.AiCenterCode][cloudbrain.Cloudbrain.Spec.AccCardType] = AccCardsNum * WorkServerNumber * (int(cloudbrain.Cloudbrain.EndTime) - int(cloudbrain.Cloudbrain.StartTime))
}
} else {
if int64(cloudbrain.Cloudbrain.StartTime) < beginTime {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.Spec.AiCenterCode][cloudbrain.Cloudbrain.Spec.AccCardType] += AccCardsNum * WorkServerNumber * (int(cloudbrain.Cloudbrain.EndTime) - int(beginTime))
} else {
cloudBrainCenterCodeAndCardType[cloudbrain.Cloudbrain.Spec.AiCenterCode][cloudbrain.Cloudbrain.Spec.AccCardType] += AccCardsNum * WorkServerNumber * (int(cloudbrain.Cloudbrain.EndTime) - int(cloudbrain.Cloudbrain.StartTime))
}
}

}
}

return cloudBrainCenterCodeAndCardType
}

func CloudbrainUpdateHistoryData(ctx *context.Context) {
beginTimeStr := ctx.QueryTrim("beginTime")
endTimeStr := ctx.QueryTrim("endTime")
beginTime, _ := time.ParseInLocation("2006-01-02 15:04:05", beginTimeStr, time.Local)
endTime, _ := time.ParseInLocation("2006-01-02 15:04:05", endTimeStr, time.Local)
beginTimeUnix := timeutil.TimeStamp(beginTime.Unix())
endTimeUnix := timeutil.TimeStamp(endTime.Unix())

err := models.DeleteCloudbrainDurationStatistic(beginTimeUnix, endTimeUnix)
count := UpdateDurationStatisticHistoryData(beginTime, endTime)
ctx.JSON(http.StatusOK, map[string]interface{}{
"message": 0,
"count": count,
"err": err,
})
}

+ 70
- 12
routers/repo/grampus.go View File

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

import (
"code.gitea.io/gitea/modules/urfs_client/urchin"
"encoding/json"
"errors"
"fmt"
@@ -12,6 +11,9 @@ import (
"strconv"
"strings"

"code.gitea.io/gitea/modules/urfs_client/urchin"
"code.gitea.io/gitea/routers/response"

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

"code.gitea.io/gitea/modules/dataset"
@@ -861,10 +863,10 @@ func GrampusTrainJobShow(ctx *context.Context) {
}
}
}
err = models.UpdateJob(task)
if err != nil {
log.Error("UpdateJob failed:" + err.Error())
}
}
err = models.UpdateJob(task)
if err != nil {
log.Error("UpdateJob failed:" + err.Error())
}
}
}
@@ -936,15 +938,14 @@ func GrampusGetLog(ctx *context.Context) {
content, err := grampus.GetTrainJobLog(job.JobID)
if err != nil {
log.Error("GetTrainJobLog failed: %v", err, ctx.Data["MsgID"])
ctx.ServerError(err.Error(), err)
ctx.JSON(http.StatusOK, map[string]interface{}{
"JobName": job.JobName,
"Content": "",
"CanLogDownload": false,
})
return
}
var canLogDownload bool
if err != nil {
canLogDownload = false
} else {
canLogDownload = true
}
canLogDownload := err == nil && job.IsUserHasRight(ctx.User)
ctx.JSON(http.StatusOK, map[string]interface{}{
"JobName": job.JobName,
"Content": content,
@@ -954,6 +955,28 @@ func GrampusGetLog(ctx *context.Context) {
return
}

func GrampusMetrics(ctx *context.Context) {
jobID := ctx.Params(":jobid")
job, err := models.GetCloudbrainByJobID(jobID)
if err != nil {
log.Error("GetCloudbrainByJobID failed: %v", err, ctx.Data["MsgID"])
ctx.ServerError(err.Error(), err)
return
}

result, err := grampus.GetGrampusMetrics(job.JobID)
if err != nil {
log.Error("GetTrainJobLog failed: %v", err, ctx.Data["MsgID"])
}
ctx.JSON(http.StatusOK, map[string]interface{}{
"JobID": jobID,
"Interval": result.Interval,
"MetricsInfo": result.MetricsInfo,
})

return
}

func generateCommand(repoName, processorType, codeRemotePath, dataRemotePath, bootFile, paramSrc, outputRemotePath, datasetName, pretrainModelPath, pretrainModelFileName, modelRemoteObsUrl string) (string, error) {
var command string

@@ -1100,3 +1123,38 @@ func downloadZipCode(ctx *context.Context, codePath, branchName string) error {

return nil
}
func HandleTaskWithAiCenter(ctx *context.Context) {
log.Info("HandleTaskWithAiCenter start")
updateCounts := 0
cloudBrains, err := models.GetC2NetWithAiCenterWrongJob()
if err != nil {
log.Error("GetC2NetWithAiCenterWrongJob failed:" + err.Error())
return
}
if len(cloudBrains) == 0 {
log.Info("HandleC2NetWithAiCenterWrongJob:no task need handle")
return
}
cloudBrainCounts := len(cloudBrains)
for _, task := range cloudBrains {
result, err := grampus.GetJob(task.JobID)
if err != nil {
log.Error("GetJob failed:" + err.Error())
continue
}
if len(result.JobInfo.Tasks) != 0 {
if len(result.JobInfo.Tasks[0].CenterID) == 1 && len(result.JobInfo.Tasks[0].CenterName) == 1 {
task.AiCenter = result.JobInfo.Tasks[0].CenterID[0] + "+" + result.JobInfo.Tasks[0].CenterName[0]
}
err = models.UpdateJob(task)
if err != nil {
log.Error("UpdateJob failed:" + err.Error())
}
updateCounts++
}
}
r := make(map[string]interface{}, 0)
r["cloudBrainCounts"] = cloudBrainCounts
r["updateCounts"] = updateCounts
ctx.JSON(http.StatusOK, response.SuccessWithData(r))
}

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

@@ -645,6 +645,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Group("/specification", func() {
m.Get("", admin.GetSpecificationPage)
m.Get("/list", admin.GetResourceSpecificationList)
m.Get("/list/all", admin.GetAllResourceSpecificationList)
m.Get("/scenes/:id", admin.GetResourceSpecificationScenes)
m.Post("/grampus/sync", admin.SyncGrampusSpecs)
m.Post("/add", binding.Bind(models.ResourceSpecificationReq{}), admin.AddResourceSpecification)
@@ -728,6 +729,13 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Post("/complete_multipart", repo.CompleteMultipart)
})

m.Group("/attachments/model", func() {
m.Get("/get_chunks", repo.GetModelChunks)
m.Get("/new_multipart", repo.NewModelMultipart)
m.Get("/get_multipart_url", repo.GetModelMultipartUploadUrl)
m.Post("/complete_multipart", repo.CompleteModelMultipart)
})

m.Group("/attachments", func() {
m.Get("/public/query", repo.QueryAllPublicDataset)
m.Get("/private/:username", repo.QueryPrivateDataset)
@@ -1228,6 +1236,12 @@ func RegisterRoutes(m *macaron.Macaron) {
})
}, context.RepoRef())
m.Group("/modelmanage", func() {
m.Get("/create_local_model_1", repo.CreateLocalModel)
m.Get("/create_local_model_2", repo.CreateLocalModelForUpload)
m.Get("/create_online_model", repo.CreateOnlineModel)
m.Post("/create_local_model", repo.SaveLocalModel)
m.Delete("/delete_model_file", repo.DeleteModelFile)

m.Post("/create_model", repo.SaveModel)
m.Post("/create_model_convert", reqWechatBind, reqRepoModelManageWriter, repo.SaveModelConvert)
m.Post("/create_new_model", repo.SaveNewNameModel)
@@ -1487,6 +1501,12 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Get("/record/list", point.GetPointRecordList)
}, reqSignIn)

m.Group("/resources", func() {
m.Group("/queue", func() {
m.Get("/centers", admin.GetResourceAiCenters)
})
})

if setting.API.EnableSwagger {
m.Get("/swagger.v1.json", templates.JSONRenderer(), routers.SwaggerV1Json)
}


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

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

@@ -837,6 +839,8 @@ func Cloudbrains(ctx *context.Context) {
}
models.LoadSpecs4CloudbrainInfo(ciTasks)
for i, _ := range ciTasks {
ciTasks[i] = cloudbrainService.UpdateCloudbrainAiCenter(ciTasks[i])
ciTasks[i].Cloudbrain.AiCenter = repo.GetAiCenterNameByCode(ciTasks[i].Cloudbrain.AiCenter, ctx.Language())
ciTasks[i].CanDebug = true
ciTasks[i].CanDel = true
ciTasks[i].Cloudbrain.ComputeResource = ciTasks[i].ComputeResource


+ 1
- 1
services/cloudbrain/cloudbrainTask/sync_status.go View File

@@ -14,7 +14,7 @@ import (
var noteBookOKMap = make(map[int64]int, 20)

//if a task notebook url can get two times, the notebook can browser.
const successfulCount = 2
const successfulCount = 3

func SyncCloudBrainOneStatus(task *models.Cloudbrain) (*models.Cloudbrain, error) {
jobResult, err := cloudbrain.GetJob(task.JobID)


+ 1
- 1
services/cloudbrain/resource/resource_queue.go View File

@@ -16,7 +16,7 @@ func AddResourceQueue(req models.ResourceQueueReq) error {
}

func UpdateResourceQueue(queueId int64, req models.ResourceQueueReq) error {
if _, err := models.UpdateResourceQueueById(queueId, models.ResourceQueue{
if _, err := models.UpdateResourceCardsTotalNum(queueId, models.ResourceQueue{
CardsTotalNum: req.CardsTotalNum,
Remark: req.Remark,
}); err != nil {


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

@@ -130,10 +130,49 @@ func GetResourceSpecificationList(opts models.SearchResourceSpecificationOptions
if err != nil {
return nil, err
}

return models.NewResourceSpecAndQueueListRes(n, r), nil
}

//GetAllDistinctResourceSpecification returns specification and queue after distinct
//totalSize is always 0 here
func GetAllDistinctResourceSpecification(opts models.SearchResourceSpecificationOptions) (*models.ResourceSpecAndQueueListRes, error) {
opts.Page = 0
opts.PageSize = 1000
opts.OrderBy = models.SearchSpecOrder4Standard
_, r, err := models.SearchResourceSpecification(opts)
if err != nil {
return nil, err
}
nr := distinctResourceSpecAndQueue(r)
return models.NewResourceSpecAndQueueListRes(0, nr), nil
}

func distinctResourceSpecAndQueue(r []models.ResourceSpecAndQueue) []models.ResourceSpecAndQueue {
specs := make([]models.ResourceSpecAndQueue, 0, len(r))
sourceSpecIdMap := make(map[string]models.ResourceSpecAndQueue, 0)
for i := 0; i < len(r); i++ {
spec := r[i]
if spec.SourceSpecId == "" {
specs = append(specs, spec)
continue
}
if _, has := sourceSpecIdMap[spec.SourceSpecId]; has {
//prefer to use on-shelf spec
if sourceSpecIdMap[spec.SourceSpecId].Status != spec.Status && spec.Status == models.SpecOnShelf {
for k, v := range specs {
if v.ResourceSpecification.ID == sourceSpecIdMap[spec.SourceSpecId].ResourceSpecification.ID {
specs[k] = spec
}
}
}
continue
}
specs = append(specs, spec)
sourceSpecIdMap[spec.SourceSpecId] = spec
}
return specs
}

func GetResourceSpecificationScenes(specId int64) ([]models.ResourceSceneBriefRes, error) {
r, err := models.GetSpecScenes(specId)
if err != nil {
@@ -200,6 +239,7 @@ func AddSpecOperateLog(doerId int64, operateType string, newValue, oldValue *mod
}

func FindAvailableSpecs(userId int64, opts models.FindSpecsOptions) ([]*models.Specification, error) {
opts.SpecStatus = models.SpecOnShelf
r, err := models.FindSpecs(opts)
if err != nil {
log.Error("FindAvailableSpecs error.%v", err)


+ 40
- 0
services/cloudbrain/util.go View File

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


"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/setting"
)
@@ -34,6 +36,7 @@ func GetAiCenterShow(aiCenter string, ctx *context.Context) string {
return ""

}

func GetDisplayJobName(username string) string {
t := time.Now()
return jobNamePrefixValid(cutString(username, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:]
@@ -54,5 +57,42 @@ func jobNamePrefixValid(s string) string {

re = regexp.MustCompile(`^[_\\-]+`)
return re.ReplaceAllString(removeSpecial, "")
}

func GetAiCenterInfoByCenterCode(aiCenterCode string) *setting.C2NetSequenceInfo {
if setting.AiCenterCodeAndNameMapInfo != nil {
if info, ok := setting.AiCenterCodeAndNameMapInfo[aiCenterCode]; ok {
return info
} else {
return nil
}
} else {
return nil
}
}

func getAiCenterCode(aiCenter string) string {
aiCenterInfo := strings.Split(aiCenter, "+")
return aiCenterInfo[0]
}

func UpdateCloudbrainAiCenter(cloudbrain *models.CloudbrainInfo) *models.CloudbrainInfo {
if cloudbrain.Cloudbrain.Type == models.TypeCloudBrainOne {
cloudbrain.Cloudbrain.AiCenter = models.AICenterOfCloudBrainOne
cloudbrain.Cloudbrain.Cluster = models.OpenICluster
}
if cloudbrain.Cloudbrain.Type == models.TypeCloudBrainTwo {
cloudbrain.Cloudbrain.AiCenter = models.AICenterOfCloudBrainTwo
cloudbrain.Cloudbrain.Cluster = models.OpenICluster
}
if cloudbrain.Cloudbrain.Type == models.TypeCDCenter {
cloudbrain.Cloudbrain.AiCenter = models.AICenterOfChengdu
cloudbrain.Cloudbrain.Cluster = models.OpenICluster
}
if cloudbrain.Cloudbrain.Type == models.TypeC2Net {
cloudbrain.Cloudbrain.AiCenter = getAiCenterCode(cloudbrain.Cloudbrain.AiCenter)
cloudbrain.Cloudbrain.Cluster = models.C2NetCluster
}

return cloudbrain
}

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

@@ -170,7 +170,7 @@
</div>
<!-- 智算中心 -->
<div class="one wide column text center nowrap" style="width:8% !important;">
<span style="font-size: 12px;" class="aicenter_{{.DisplayJobName}}_{{$JobID}}">{{if .AiCenter}}{{.AiCenter}}{{else}}--{{end}}</span>
<span style="font-size: 12px;" class="aicenter_{{.DisplayJobName}}_{{$JobID}}" title="{{if .AiCenter}}{{.AiCenter}}{{else}}--{{end}}">{{if .AiCenter}}{{.AiCenter}}{{else}}--{{end}}</span>
</div>
<!-- XPU类型 -->
<div class="one wide column text center nowrap" style="width:8% !important;">
@@ -184,16 +184,16 @@
spanEl.setAttribute('title', cardType);
spanEl.innerText = cardType;
var cluster = spec.Cluster || '--';
var cluster = {{.Cluster}} || '--';
var clusterName = document.querySelector('.cloudbrain_debug').dataset['cluster' + cluster[0] + cluster.toLocaleLowerCase().slice(1)] || '--';
spanEl = document.querySelector('.cluster_{{.DisplayJobName}}_{{$JobID}}');
spanEl.setAttribute('title', cluster);
spanEl.innerText = clusterName;

var aiCenter = spec.AiCenterName || '--';
spanEl = document.querySelector('.aicenter_{{.DisplayJobName}}_{{$JobID}}');
spanEl.setAttribute('title', aiCenter);
spanEl.innerText = aiCenter;
// var aiCenter = spec.AiCenterName || '--';
// spanEl = document.querySelector('.aicenter_{{.DisplayJobName}}_{{$JobID}}');
// spanEl.setAttribute('title', aiCenter);
// spanEl.innerText = aiCenter;
})();
</script>
<!-- 创建者 -->


+ 4
- 6
templates/admin/cloudbrain/search.tmpl View File

@@ -71,22 +71,20 @@
document.addEventListener('DOMContentLoaded', function() {
$.ajax({
type: "GET",
url: "/api/v1/cloudbrain/get_center_info",
url: "/api/v1/cloudbrainboard/cloudbrain/resource_queues",
dataType: "json",
data: {},
success: function (res) {
var data = res || [];
var data = res.resourceQueues || [];
var aiCenterSelEl = $('#aiCenter-sel');
var itemEl = aiCenterSelEl.find('.menu .item').eq(0);
var selectAiCenterCode = aiCenterSelEl.find('.default').attr('aicenter');
var selectAiCenterName = '';
var lang = document.querySelector('html').getAttribute('lang') || 'en-US';
var except = ['', 'more'];
for (var i = 0, iLen = data.length; i < iLen; i++) {
var dataI = data[i];
var aiCenterCode = dataI.name;
if (except.indexOf(aiCenterCode) >= 0) continue;
var aiCenterName = lang === 'en-US' ? dataI.content_en : dataI.content;
var aiCenterCode = dataI.AiCenterCode;
var aiCenterName = dataI.AiCenterName;
var itemClone = itemEl.clone();
var oHref = itemClone.attr('href');
var oId = itemClone.attr('id');


+ 4
- 6
templates/admin/cloudbrain/search_dashboard.tmpl View File

@@ -85,22 +85,20 @@
document.addEventListener('DOMContentLoaded', function() {
$.ajax({
type: "GET",
url: "/api/v1/cloudbrain/get_center_info",
url: "/api/v1/cloudbrainboard/cloudbrain/resource_queues",
dataType: "json",
data: {},
success: function (res) {
var data = res || [];
var data = res.resourceQueues || [];
var aiCenterSelEl = $('#aiCenter-sel');
var itemEl = aiCenterSelEl.find('.menu .item').eq(0);
var selectAiCenterCode = aiCenterSelEl.find('.default').attr('aicenter');
var selectAiCenterName = '';
var lang = document.querySelector('html').getAttribute('lang') || 'en-US';
var except = ['', 'more'];
for (var i = 0, iLen = data.length; i < iLen; i++) {
var dataI = data[i];
var aiCenterCode = dataI.name;
if (except.indexOf(aiCenterCode) >= 0) continue;
var aiCenterName = lang === 'en-US' ? dataI.content_en : dataI.content;
var aiCenterCode = dataI.AiCenterCode;
var aiCenterName = dataI.AiCenterName;
var itemClone = itemEl.clone();
var oHref = itemClone.attr('href');
var oId = itemClone.attr('id');


+ 21
- 2
templates/base/footer_content.tmpl View File

@@ -24,11 +24,30 @@
<div class="text">{{.LangName}}</div>
<div class="menu">
{{range .AllLangs}}
<a lang="{{.Lang}}" class="item {{if eq $.Lang .Lang}}active selected{{end}}" href="{{if eq $.Lang .Lang}}#{{else}}{{$.Link}}?lang={{.Lang}}{{end}}">{{.Name}}</a>
<!-- <a lang="{{.Lang}}" class="item {{if eq $.Lang .Lang}}active selected{{end}}" href="{{if eq $.Lang .Lang}}#{{else}}{{$.Link}}?lang={{.Lang}}{{end}}">{{.Name}}</a> -->
<a lang="{{.Lang}}" class="item {{if eq $.Lang .Lang}}active selected{{end}}" href="javascript:;" olang="{{$.Lang}}" lang="{{.Lang}}" >{{.Name}}</a>
{{end}}
</div>
</div>

<script>
;(function() {
document.addEventListener('DOMContentLoaded', function() {
$('.ui.language .menu .item').on('click', function() {
var lang = $(this).attr('lang');
var oLang = $(this).attr('olang');
if (oLang === lang) return;
var origin = window.location.origin;
var pathname = window.location.pathname;
var search = window.location.search;
var hash = window.location.hash;
var oHref = window.location.href;
var urlSearchParams = new URLSearchParams(search);
urlSearchParams.set('lang', lang);
window.location.href = origin + pathname + '?' + urlSearchParams.toString() + hash;
});
});
})();
</script>
<a href="https://git.openi.org.cn/zeizei/OpenI_Learning" class="item" target="_blank"><i class="compass icon" ></i> {{.i18n.Tr "custom.Platform_Tutorial"}}</a>
{{if .EnableSwagger}}<a href="/api/swagger" class="item"><i class="plug icon"></i> API</a>{{end}}
{{if .IsSigned}}


+ 21
- 1
templates/base/footer_content_fluid.tmpl View File

@@ -22,10 +22,30 @@
<div class="text">{{.LangName}}</div>
<div class="menu">
{{range .AllLangs}}
<a lang="{{.Lang}}" class="item {{if eq $.Lang .Lang}}active selected{{end}}" href="{{if eq $.Lang .Lang}}#{{else}}{{$.Link}}?lang={{.Lang}}{{end}}">{{.Name}}</a>
<!--<a lang="{{.Lang}}" class="item {{if eq $.Lang .Lang}}active selected{{end}}" href="{{if eq $.Lang .Lang}}#{{else}}{{$.Link}}?lang={{.Lang}}{{end}}">{{.Name}}</a>-->
<a lang="{{.Lang}}" class="item {{if eq $.Lang .Lang}}active selected{{end}}" href="javascript:;" olang="{{$.Lang}}" lang="{{.Lang}}" >{{.Name}}</a>
{{end}}
</div>
</div>
<script>
;(function() {
document.addEventListener('DOMContentLoaded', function() {
$('.ui.language .menu .item').on('click', function() {
var lang = $(this).attr('lang');
var oLang = $(this).attr('olang');
if (oLang === lang) return;
var origin = window.location.origin;
var pathname = window.location.pathname;
var search = window.location.search;
var hash = window.location.hash;
var oHref = window.location.href;
var urlSearchParams = new URLSearchParams(search);
urlSearchParams.set('lang', lang);
window.location.href = origin + pathname + '?' + urlSearchParams.toString() + hash;
});
});
})();
</script>
<a href="https://git.openi.org.cn/zeizei/OpenI_Learning" class="item" target="_blank"><i class="compass icon"></i> {{.i18n.Tr "custom.Platform_Tutorial"}} </a>
{{if .EnableSwagger}}<a href="/api/swagger" class="item"><i class="plug icon" ></i> API</a>{{end}}
{{if .IsSigned}}


+ 0
- 71
templates/repo/cloudbrain/inference/show.tmpl View File

@@ -262,8 +262,6 @@
<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>
<a class="item" data-tab="second"
onclick="javascript:parseInfo()">{{$.i18n.Tr "repo.cloudbrain.runinfo"}}</a>
<a class="item log_bottom" data-tab="third"
data-version="{{.VersionName}}">{{$.i18n.Tr "repo.modelarts.log"}}</a>
<a class="item load-model-file" data-tab="four"
@@ -515,25 +513,6 @@

</div>
</div>

<div class="ui tab" data-tab="second">
<div>
<div class="ui message message{{.VersionName}}" style="display: none;">
<div id="header"></div>
</div>
<div class="ui attached"
style="height: 390px !important; overflow: auto;">
<input type="hidden" id="json_value" value="{{$.result.JobStatus.AppExitDiagnostics}}">
<input type="hidden" id="ExitDiagnostics" value="{{$.ExitDiagnostics}}">
<span id="info_display" class="info_text">

</span>
</div>

</div>

</div>

<div class="ui tab" data-tab="third">
<div class="file-info">
<a id="{{.VersionName}}-log-down"
@@ -616,56 +595,6 @@
$(document).ready(function () {
$('.secondary.menu .item').tab();
});

let userName
let repoPath
let jobID
let downlaodFlag = {{ $.canDownload }}
let taskID = {{ $.task.ID }}
let realJobName = {{ $.task.JobName }}
function parseInfo() {
let jsonValue = document.getElementById("json_value").value;
let jsonObj = JSON.parse(jsonValue);
let podRoleName = jsonObj["podRoleName"];
let html = "";
if (podRoleName != null) {
let task0 = podRoleName["task1-0"];
let podEvents = jsonObj["podEvents"];
let podEventArray = podEvents[task0];
if (podEventArray != null) {
for (var i = 0; i < podEventArray.length; i++) {
if (podEventArray[i]["reason"] != "") {
html += "<p><b>[" + podEventArray[i]["reason"] + "]</b></p>";
html += "<p>" + podEventArray[i]["message"] + "</p>";
html += "<p>" + podEventArray[i]["action"] + "</p>";
}
}
}
let extras = jsonObj["extras"];
if (extras != null) {
for (var i = 0; i < extras.length; i++) {
if (extras[i]["reason"] != "") {
html += "<p><b>[" + extras[i]["reason"] + "]</b></p>";
html += "<p>" + extras[i]["message"] + "</p>";
html += "<p>" + extras[i]["action"] + "</p>";
}
}
}
}

let string = document.getElementById("ExitDiagnostics").value;
string = string.replace(/\r\n/g, "<br>")
string = string.replace(/\n/g, "<br>");
string = string.replace(/(\r\n)|(\n)/g, '<br>');

if (string != "") {
html += "<p><b>[ExitDiagnostics]</b></p>";
html += "<p>" + string + "</p>";
}

document.getElementById("info_display").innerHTML = html;
}

;(function() {
var SPEC = {{ .Spec }};
var showPoint = false;


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

@@ -284,15 +284,10 @@
<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="javascript:parseInfo()">{{$.i18n.Tr "repo.cloudbrain.runinfo"}}</a>
data-tab="first{{$k}}">{{$.i18n.Tr "repo.modelarts.train_job.config"}}</a>

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

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


<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "repo.modelarts.train_job.run_parameter"}}
@@ -504,25 +496,6 @@

</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_state{{.VersionName}}"
style="height: 390px !important; overflow: auto;">
<input type="hidden" id="json_value" value="{{$.result.JobStatus.AppExitDiagnostics}}">
<input type="hidden" id="ExitDiagnostics" value="{{$.ExitDiagnostics}}">
<span id="info_display" class="info_text">

</span>
</div>

</div>

</div>

<div class="ui tab" data-tab="third{{$k}}">
<div class="file-info">
<a id="{{.VersionName}}-log-down"
@@ -565,29 +538,22 @@
<input type="hidden" name="init_log" value>
<pre id="log_file{{.VersionName}}"></pre>
</div>

</div>

</div>

<div class="ui tab" data-tab="four{{$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">result</div>
<div class="divider"> / </div>

</div>
<div id="dir_list{{.VersionName}}">

</div>
<div style="display:flex;align-items: center;justify-content: end;color: #f2711c;">
<i class="ri-error-warning-line" style="margin-right:0.5rem;"></i>
<span>{{$.i18n.Tr "repo.file_limit_100"}}</span>
</div>
</div>

</div>
</div>
</div>
@@ -700,11 +666,8 @@
<button class="ui button cancel">{{.i18n.Tr "repo.cloudbrain.cancel"}}</button>
</div>
</div>


</div>
</div>

</div>
{{template "base/footer" .}}
<script type="text/javascript" src="/self/ztree/js/jquery.ztree.core.js"></script>
@@ -712,7 +675,15 @@
<script src="{{StaticUrlPrefix}}/js/specsuse.js?v={{MD5 AppVer}}" type="text/javascript"></script>

<script>
var setting = {
var userName;
var repoPath;
$(document).ready(function(){
var url = window.location.href;
var urlArr = url.split('/')
userName = urlArr.slice(-5)[0]
repoPath = urlArr.slice(-4)[0]
});
var setting = {
check: {
enable: true,
chkboxType: {"Y":"ps", "N":"ps"}
@@ -922,110 +893,7 @@
$('.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兼容
}
}

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

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

function parseInfo() {
let jsonValue = document.getElementById("json_value").value;
let jsonObj = JSON.parse(jsonValue);
let podRoleName = jsonObj["podRoleName"];
let html = "";
if (podRoleName != null) {
let task0 = podRoleName["task1-0"];
let podEvents = jsonObj["podEvents"];
let podEventArray = podEvents[task0];
if (podEventArray != null) {
for (var i = 0; i < podEventArray.length; i++) {
if (podEventArray[i]["reason"] != "") {
html += "<p><b>[" + podEventArray[i]["reason"] + "]</b></p>";
html += "<p>" + podEventArray[i]["message"] + "</p>";
html += "<p>" + podEventArray[i]["action"] + "</p>";
}
}
}
let extras = jsonObj["extras"];
if (extras != null) {
for (var i = 0; i < extras.length; i++) {
if (extras[i]["reason"] != "") {
html += "<p><b>[" + extras[i]["reason"] + "]</b></p>";
html += "<p>" + extras[i]["message"] + "</p>";
html += "<p>" + extras[i]["action"] + "</p>";
}
}
}
}

let string = document.getElementById("ExitDiagnostics").value;
string = string.replace(/\r\n/g, "<br>")
string = string.replace(/\n/g, "<br>");
string = string.replace(/(\r\n)|(\n)/g, '<br>');

if (string != "") {
html += "<p><b>[ExitDiagnostics]</b></p>";
html += "<p>" + string + "</p>";
}

document.getElementById("info_display").innerHTML = html;
}

;(function() {
var SPEC = {{ .Spec }};
var showPoint = false;


+ 11
- 5
templates/repo/grampus/trainjob/show.tmpl View File

@@ -238,11 +238,8 @@
<span>
<div style="float: right;">
{{$.CsrfTokenHtml}}
</div>
<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.current_version"}}:{{.VersionName}}</span>
@@ -260,7 +257,6 @@
<span class="refresh-status" data-tooltip="刷新" style="cursor: pointer;" data-inverted="" data-version="{{.VersionName}}">
<i class="redo icon redo-color"></i>
</span>

</div>
<div style="float: right;">
{{if and ($.canDownload) (ne .Status "WAITING") ($.Permission.CanWrite $.UnitTypeModelManage) }}
@@ -269,7 +265,6 @@
{{else}}
<a class="ti-action-menu-item disabled" id="{{.VersionName}}-create-model">{{$.i18n.Tr "repo.modelarts.create_model"}}</a>
{{end}}

</div>
</span>
</span>
@@ -282,6 +277,9 @@

<a class="active item" data-tab="first{{$k}}">{{$.i18n.Tr "repo.modelarts.train_job.config"}}</a>
<a class="item log_bottom" data-tab="second{{$k}}" data-version="{{.VersionName}}">{{$.i18n.Tr "repo.modelarts.log"}}</a>
{{ if eq $.Spec.ComputeResource "NPU"}}
<a class="item metric_chart" data-tab="four{{$k}}" data-version="{{.VersionName}}" data-path="{{$.RepoRelPath}}/grampus/train-job/{{.JobID}}/metrics">{{$.i18n.Tr "cloudbrain.resource_use"}}</a>
{{end}}
<a class="item load-model-file" data-tab="third{{$k}}" data-download-flag="{{$.canDownload}}" data-path="{{$.RepoLink}}/modelarts/train-job/{{.JobID}}/model_list" data-version="{{.VersionName}}" data-parents="" data-filename="" data-init="init" >{{$.i18n.Tr "repo.model_download"}}</a>
</div>
<div class="ui tab active" data-tab="first{{$k}}">
@@ -564,6 +562,14 @@

</div>

</div>
<div class="ui tab" data-tab="four{{$k}}" style="position: relative;">
<i class="ri-refresh-line metric_chart"
style="position: absolute;right: 25%;color:#3291f8;z-index:99;cursor: pointer;"
data-version="{{.VersionName}}"></i>
<div id="metric-{{.VersionName}}" style="height: 260px;width: 870px;">
</div>
</div>
<div class="ui tab" data-tab="third{{$k}}">
<input type="hidden" name="model{{.VersionName}}" value="-1">


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

@@ -321,7 +321,7 @@
data-tab="first{{$k}}">{{$.i18n.Tr "repo.modelarts.train_job.config"}}</a>
<a class="item log_bottom" data-tab="second{{$k}}"
data-version="{{.VersionName}}">{{$.i18n.Tr "repo.modelarts.log"}}</a>
<a class="item metric_chart" data-tab="four{{$k}}" data-version="{{.VersionName}}">{{$.i18n.Tr "cloudbrain.resource_use"}}</a>
<a class="item metric_chart" data-tab="four{{$k}}" data-version="{{.VersionName}}" data-path="{{$.RepoRelPath}}/modelarts/train-job/{{.JobID}}/metric_statistics?version_name={{.VersionName}}&statistic_type=each&metrics=">{{$.i18n.Tr "cloudbrain.resource_use"}}</a>
<a class="item load-model-file" data-tab="third{{$k}}" data-download-flag="{{$.canDownload}}" data-path="{{$.RepoLink}}/modelarts/train-job/{{.JobID}}/model_list" data-version="{{.VersionName}}" data-parents="" data-filename="" data-init="init" >{{$.i18n.Tr "repo.model_download"}}</a>
</div>
<div class="ui tab active" data-tab="first{{$k}}">
@@ -726,13 +726,12 @@

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

<script type="text/javascript" src="/self/ztree/js/jquery.ztree.core.js"></script>
<script type="text/javascript" src="/self/ztree/js/jquery.ztree.excheck.js"></script>
<script>
<script>
var setting = {
check: {
enable: true,


+ 10
- 0
templates/repo/modelmanage/create_local_1.tmpl View File

@@ -0,0 +1,10 @@
{{template "base/head" .}}
<link rel="stylesheet" href="{{StaticUrlPrefix}}/css/vp-modelmanage-local-create-1.css?v={{MD5 AppVer}}" />
<div class="repository release dataset-list view">
{{template "repo/header" .}}
<div class="ui container">
<div id="__vue-root"></div>
</div>
</div>
<script src="{{StaticUrlPrefix}}/js/vp-modelmanage-local-create-1.js?v={{MD5 AppVer}}"></script>
{{template "base/footer" .}}

+ 11
- 0
templates/repo/modelmanage/create_local_2.tmpl View File

@@ -0,0 +1,11 @@
{{template "base/head" .}}
<link rel="stylesheet" href="{{StaticUrlPrefix}}/css/vp-modelmanage-local-create-2.css?v={{MD5 AppVer}}" />
<div class="repository release dataset-list view">
{{template "repo/header" .}}
<script>var MAX_MODEL_SIZE = {{ .max_model_size }};</script>
<div class="ui container">
<div id="__vue-root"></div>
</div>
</div>
<script src="{{StaticUrlPrefix}}/js/vp-modelmanage-local-create-2.js?v={{MD5 AppVer}}"></script>
{{template "base/footer" .}}

+ 581
- 0
templates/repo/modelmanage/create_online.tmpl View File

@@ -0,0 +1,581 @@
{{template "base/head" .}}
<link rel="stylesheet" href="/self/ztree/css/zTreeStyle/zTreeStyle.css" type="text/css">
<style>
#newmodel .header {
height: 45px;
border: 1px solid #d4d4d5;
border-radius: 5px 5px 0 0;
font-size: 14px;
background: #f0f0f0;
display: flex;
align-items: center;
}
#newmodel .content {
margin-top: -1px;
border: 1px solid #d4d4d5;
border-top: none;
}
.inline.fields .right.aligned label{
width: 100% !important;
text-align: right;
}
.inline .ui.dropdown .text {
color: rgba(0, 0, 0, .87) !important;
max-width: 360px;
}
.newtext{
margin-left: 12px !important
}
.menuContent{
position: absolute;
background: #ffffff;
left: 0;
right: 26px;
top: 36px;
z-index:999;
border: 1px solid #96c8da;
border-top: 0;
border-bottom-right-radius: 4px;
border-bottom-left-radius: 4px;
box-shadow: 0 2px 3px 0 rgb(34 36 38 / 15%);
}
</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>
{{$repository := .Repository.ID}}
<div class="repository release dataset-list view">
{{template "repo/header" .}}
<div class="ui container">
<div id="newmodel">
<div class="ui second">
<div class="header" style="padding: 1rem;background-color: rgba(240, 240, 240, 100);">
<h4 id="model_header">{{.i18n.Tr "repo.model.manage.import_online_model"}}</h4>
</div>
<div class="content content-padding">
<form id="formId" class="ui form dirty">
<input class="ays-ignore" type="hidden" name="initModel" value="{{$.MODEL_COUNT}}">
<div class="ui error message"></div>
<input class="ays-ignore" type="hidden" name="_csrf" value="">
<div class="inline fields">
<div class="required two wide field right aligned">
<label for="jobId">{{.i18n.Tr "repo.model.manage.select.trainjob"}}</label>
</div>
<div class="required thirteen wide inline field">
<div class="ui dropdown selection search loading" id="choice_model">
<input class="ays-ignore" type="hidden" id="jobId" name="jobId" required>
<div class="default text">{{.i18n.Tr "repo.model.manage.select.trainjob"}}</div>
<i class="dropdown icon"></i>
<div class="menu" id="job-name">
</div>
</div>
<label for="versionName">{{.i18n.Tr "repo.model.manage.version"}}</label>
<span>&nbsp;</span>
<div class="ui dropdown selection search" id="choice_version">
<input class="ays-ignore" type="hidden" id="versionName" name="versionName" required>
<div class="default text">{{.i18n.Tr "repo.model.manage.select.version"}}</div>
<i class="dropdown icon"></i>
<div class="menu" id="job-version">

</div>
</div>
</div>
</div>
<div class="required inline fields" id="modelname">
<div class="two wide field right aligned">
<label for="name">{{.i18n.Tr "repo.model.manage.model_name"}}</label>
</div>
<div class="eight wide field">
<input class="ays-ignore" id="name" name="name" required maxlength="25" onkeyup="this.value=this.value.replace(/[, ]/g,'')">
</div>
</div>
<div class="required inline fields" id="verionName" style="display:none;">
<div class="two wide field right aligned">
<label for="version">{{.i18n.Tr "repo.model.manage.version"}}</label>
</div>
<div class="eight wide field">
<input class="ays-ignore" id="version" name="version" value="" readonly required maxlength="255">
</div>
</div>
<div class="unite min_title inline fields required">
<div class="two wide field right aligned">
<label for="Engine">{{.i18n.Tr "repo.model.manage.engine"}}</label>
</div>
<div class="ui ten wide field dropdown selection" id="choice_Engine">
<input class="ays-ignore" type="hidden" id="engine" name="engine" required>
<div class="default text newtext">{{.i18n.Tr "repo.model.manage.select.engine"}}</div>
<i class="dropdown icon"></i>
<div class="menu" id="job-Engine">

</div>
</div>
</div>
<div class="unite min_title inline fields required">
<div class="two wide field right aligned">
<label for="modelSelectedFile">{{.i18n.Tr "repo.model.manage.modelfile"}}</label>
</div>
<div class="thirteen wide field" style="position:relative">
<input class="ays-ignore" id="modelSelectedFile" type="text" readonly required onclick="showMenu();" name="modelSelectedFile" >
<div id="menuContent" class="menuContent" style="display:none;">
<ul id="treeDemo" class="ztree"></ul>
</div>
</div>
</div>
<div class="inline fields">
<div class="two wide field right aligned">
<label for="Label">{{.i18n.Tr "repo.model.manage.modellabel"}} &nbsp</label>
</div>
<div class="thirteen wide field">
<input class="ays-ignore" id="label" name="label" maxlength="255" placeholder='{{.i18n.Tr "repo.modelarts.train_job.label_place"}}'>
</div>
</div>
<div class="inline fields">
<div class="two wide field right aligned">
<label for="description">{{.i18n.Tr "repo.model.manage.modeldesc"}} &nbsp</label>
</div>
<div class="thirteen wide field">
<textarea id="description" class="ays-ignore" 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, 256)"></textarea>
</div>
</div>
</form>
<div class="inline field" style="margin-left:140px;margin-top:28px;">
<button id="submitId" type="button" class="ui create_train_job green button" onclick="submitSaveModel()"
style="">
{{.i18n.Tr "repo.model.manage.sava_model"}}
</button>
<button style="margin-left:0px;" class="ui button cancel" onclick="backToModelListPage()">{{.i18n.Tr "repo.cloudbrain.cancel"}}</button>
</div>
</div>
</div>
</div>
</div>
</div>
{{template "base/footer" .}}
<script type="text/javascript" src="/self/ztree/js/jquery.ztree.core.js"></script>
<script type="text/javascript" src="/self/ztree/js/jquery.ztree.excheck.js"></script>
<script>
;(function() {
var setting = {
check: {
enable: true,
chkboxType: {"Y":"ps", "N":"ps"}
},
view: {
dblClickExpand: false
},
callback: {
beforeClick: beforeClick,
onCheck: onCheck
}
};

function beforeClick(treeId, treeNode) {
var zTree = $.fn.zTree.getZTreeObj("treeDemo");
zTree.checkNode(treeNode, !treeNode.checked, null, true);
return false;
}
function onCheck(e, treeId, treeNode) {
var zTree = $.fn.zTree.getZTreeObj("treeDemo"),
nodes = zTree.getCheckedNodes(true),
v = "";
for (var i=0, l=nodes.length; i<l; i++) {
if(nodes[i].isParent){
continue;
}
var pathNodes = nodes[i].getPath();
var path ="";
for(var j=0;j<pathNodes.length;j++){
if(j ==0){
path += pathNodes[j].name;
}else{
path += "/" + pathNodes[j].name;
}
}
v += path + ";";
}
if (v.length > 0 ) v = v.substring(0, v.length-1);
var cityObj = $("#modelSelectedFile");
cityObj.attr("value", v);
}
function showMenu() {
var cityObj = $("#modelSelectedFile");
var cityOffset = $("#modelSelectedFile").offset();
// $("#menuContent").css({left:cityOffset.left + "px", top:cityOffset.top + cityObj.outerHeight() + "px"}).slideDown("fast");
$("#menuContent").slideDown("fast");

$("body").bind("mousedown", onBodyDown);
}
window.showMenu = showMenu;

function hideMenu() {
$("#menuContent").fadeOut("fast");
$("body").unbind("mousedown", onBodyDown);
}
function onBodyDown(event) {
if (!(event.target.id == "menuBtn" || event.target.id == "modelSelectedFile" || event.target.id == "menuContent" || $(event.target).parents("#menuContent").length>0)) {
hideMenu();
}
}

$(document).ready(function(){
//$.fn.zTree.init($("#treeDemo"), setting, zNodes);
});
let repolink = {{.RepoLink }}
let repoId = {{ $repository }}
const { _AppSubUrl, _StaticUrlPrefix, csrf } = window.config;
$('input[name="_csrf"]').val(csrf)
let modelData;
function createModelName() {
let repoName = location.pathname.split('/')[2]
let modelName = repoName + '_model_' + Math.random().toString(36).substr(2, 4)
$('#name').val(modelName)
$('#version').val("0.0.1")
}
let dirKey="isOnlyDir--:&";
/*
function showcreate(obj) {
$('.ui.modal.second')
.modal({
centered: false,
onShow: function () {
$('input[name="version"]').addClass('model_disabled')
$('.ui.dimmer').css({ "background-color": "rgb(136, 136, 136,0.7)" })
$("#job-name").empty()
createModelName()
loadTrainList()
},
onHide: function () {
var cityObj = $("#modelSelectedFile");
cityObj.attr("value", "");
document.getElementById("formId").reset();
$('#choice_model').dropdown('clear')
$('#choice_version').dropdown('clear')
$('#choice_Engine').dropdown('clear')
$('.ui.dimmer').css({ "background-color": "" })
$('.ui.error.message').text()
$('.ui.error.message').css('display', 'none')

}
})
.modal('show')
}
*/
$('input[name="version"]').addClass('model_disabled')
$('.ui.dimmer').css({ "background-color": "rgb(136, 136, 136,0.7)" })
$("#job-name").empty()
createModelName()
loadTrainList()

$(function () {
$('#choice_model').dropdown({
onChange: function (value) {
$("#choice_version").addClass("loading")
$('#choice_version').dropdown('clear')
$("#job-version").empty()
loadTrainVersion(value)
}
})

$('#choice_version').dropdown({
onChange: function (value) {
console.log("model version:" + value);
if (modelData != null) {
for (var i = 0; i < modelData.length; i++) {
if (modelData[i].VersionName == value) {
setEngine(modelData[i]);
loadModelFile(modelData[i]);
break;
}
}
}
}
})
});

function versionAdd(version) {
let versionArray = version.split('.')
if (versionArray[2] == '9') {
if (versionArray[1] == '9') {
versionArray[0] = String(Number(versionArray[1]) + 1)
versionArray[1] = '0'
} else {
versionArray[1] = String(Number(versionArray[1]) + 1)
}
versionArray[2] = '0'
} else {
versionArray[2] = String(Number(versionArray[2]) + 1)
}
return versionArray.join('.')
}

function loadTrainList() {
$.get(`${repolink}/modelmanage/query_train_job?repoId=${repoId}`, (data) => {

const n_length = data.length
if(n_length > 0){
let train_html = ''
for (let i = 0; i < n_length; i++) {
train_html += `<div class="item" data-value="${data[i].JobID}">${data[i].DisplayJobName}</div>`
train_html += '</div>'
}
$("#job-name").append(train_html)
$("#choice_model").removeClass("loading")
$('#choice_model .default.text').text(data[0].DisplayJobName)
$('#choice_model input[name="jobId"]').val(data[0].JobID)
loadTrainVersion()
}else{
$("#choice_model").removeClass("loading")
}
})
}

function loadTrainVersion(value) {
let tmp = $('#choice_model input[name="jobId"]').val();
let jobId = !value ? $('#choice_model input[name="jobId"]').val() : value
$.get(`${repolink}/modelmanage/query_train_job_version?jobId=${jobId}`, (data) => {
const n_length = data.length
let train_html = '';
modelData = data;
for (let i = 0; i < n_length; i++) {
var VersionName = data[i].VersionName || 'V0001';
train_html += `<div class="item" data-value="${VersionName}">${VersionName}</div>`
train_html += '</div>'
}
if (data.length) {
$("#job-version").append(train_html)
$("#choice_version").removeClass("loading")
var versionName = data[0].VersionName;
if (versionName == null || versionName == "") {
versionName = "V0001";
}
$('#choice_version .default.text').text(versionName)
$('#choice_version input[name="versionName"]').val(versionName)
setEngine(data[0])
loadModelFile(data[0])
}

})
}

function loadModelFile(trainJob){
console.log("trainJob=", trainJob);
$('#choice_file').dropdown('clear')
$("#model-file").empty()
if(trainJob ==null || trainJob ==""){
console.log("trainJob is null");
}else{
let type = trainJob.Type;
if(type == 2){
if(trainJob.ComputeResource=="NPU"){
type=1;
}else{
type=0;
}
}
$.get(`${repolink}/modelmanage/query_train_model?jobName=${trainJob.JobName}&type=${type}&versionName=${trainJob.VersionName}`, (data) => {
var cityObj = $("#modelSelectedFile");
cityObj.attr("value", "");
const n_length = data.length
let file_html=''
let firstFileName =''
var zNodes=[];
var nodesMap={};
for (let i=0;i<n_length;i++){
var parentNodeMap = nodesMap;
var fileSplits = data[i].FileName.split("/");
for(let j=0;j < fileSplits.length;j++){
if(fileSplits[j] == ""){
break;
}
if(parentNodeMap[fileSplits[j]] == null){
parentNodeMap[fileSplits[j]] = {};
}
parentNodeMap = parentNodeMap[fileSplits[j]];
}
}
for (let i=0;i<n_length;i++){
var parentNodeMap = nodesMap;
var fileSplits = data[i].FileName.split("/");
for(let j=0;j < fileSplits.length;j++){
if(fileSplits[j] == ""){
if(data[i].FileName[data[i].FileName.length -1] =="/"){
if(Object.keys(parentNodeMap).length ==0){
parentNodeMap[dirKey]="true";
}
}
break;
}
parentNodeMap = parentNodeMap[fileSplits[j]];
}
}
convertToNode(zNodes,nodesMap);
$.fn.zTree.init($("#treeDemo"), setting, zNodes);
})
}
}

function convertToNode(nodeList,nodesMap){
var keyList = Object.keys(nodesMap);
keyList.sort(function(a,b){
return a-b;
});
var isFirst = true;
for(var i=0; i<keyList.length;i++){
var node = {};
node["name"] = keyList[i];
nodeList.push(node);
if(nodesMap[keyList[i]] != null && Object.keys(nodesMap[keyList[i]]).length >0){
if(nodesMap[keyList[i]][dirKey] != null){
node["open"] = false;
node["isParent"] = true;
}else{
node["children"]=[];
if(isFirst){
node["open"] = true;
isFirst= false;
}
convertToNode(node["children"],nodesMap[keyList[i]]);
}
}
}
}

function setEngine(trainJob) {
console.log("trainJob=", trainJob);
$('#choice_Engine').dropdown('clear')
$("#job-Engine").empty()
if (trainJob.EngineName != null && trainJob.EngineName != "") {
srcEngine = trainJob.EngineName.split('-')[0]
srcEngine = srcEngine.trim().toLowerCase();
let selectedText = "PyTorch";
let selectedValue = 0;
let itemHtml = "<option class=\"item\" data-value=\"0\">PyTorch</option>";
if (srcEngine == 'tensorflow') {
selectedText = "TensorFlow";
selectedValue = 1;
itemHtml += "<option class=\"active item\" data-value=\"1\">TensorFlow</option>";
} else {
itemHtml += "<option class=\"item\" data-value=\"1\">TensorFlow</option>";
}
if (srcEngine == 'mindspore') {
selectedText = "MindSpore";
selectedValue = 2;
itemHtml += "<option class=\"active item\" data-value=\"2\">MindSpore</option>";
} else {
itemHtml += "<option class=\"item\" data-value=\"2\">MindSpore</option>";
}
itemHtml += "<option class=\"item\" data-value=\"4\">PaddlePaddle</option>"
itemHtml += "<option class=\"item\" data-value=\"5\">OneFlow</option>"
itemHtml += "<option class=\"item\" data-value=\"6\">MXNet</option>"
itemHtml += "<option class=\"item\" data-value=\"3\">Other</option>"

$('#choice_Engine .default.text').text(selectedText)
$('#choice_Engine input[name="engine"]').val(selectedValue)
$("#job-Engine").append(itemHtml);
$("#choice_Engine").removeClass('disabled');
} else {
let itemHtml = "<option class=\"active item\" data-value=\"0\">PyTorch</option>";
itemHtml += "<option class=\"item\" data-value=\"1\">TensorFlow</option>"
itemHtml += "<option class=\"item\" data-value=\"2\">MindSpore</option>"
itemHtml += "<option class=\"item\" data-value=\"4\">PaddlePaddle</option>"
itemHtml += "<option class=\"item\" data-value=\"5\">OneFlow</option>"
itemHtml += "<option class=\"item\" data-value=\"6\">MXNet</option>"
itemHtml += "<option class=\"item\" data-value=\"3\">Other</option>"
$('#choice_Engine .default.text').text("PyTorch");
$('#choice_Engine input[name="engine"]').val(0)
$("#job-Engine").append(itemHtml);
$("#choice_Engine").removeClass('disabled');
}
}

function check() {
let jobid = document.getElementById("jobId").value;
let versionname = document.getElementById("versionName").value;
let name = document.getElementById("name").value;
let version = document.getElementById("version").value;
let modelSelectedFile = document.getElementById("modelSelectedFile").value;
if (name == "") {
$("#modelname").closest('.required').addClass("error");
return false;
} else {
$("#modelname").closest('.required').removeClass("error");
}
if (versionname == "") {
$("#verionname").closest('.required').addClass("error");
return false;
} else {
$("#verionname").closest('.required').removeClass("error");
}
if (jobid == "") {
$("#jobId").closest('.required').addClass("error");
return false;
} else {
$("#jobId").closest('.required').removeClass("error");
}
if (modelSelectedFile == "") {
$("#modelSelectedFile").closest('.required').addClass("error");
return false;
} else {
$("#modelSelectedFile").closest('.required').removeClass("error");
}
if (versionname == "") {
$("#versionName").closest('.required').addClass("error");
return false;
} else {
$("#versionName").closest('.required').removeClass("error");
}
return true;
}

function submitSaveModel() {
let flag = check();
if (!flag) return false;
$(".ui.error.message").hide();
let cName = $("input[name='name']").val();
let version = $("input[name='version']").val();
let data = $("#formId").serialize();
const initModel = $("input[name='initModel']").val();
let url_href = location.href.split("create_online_model")[0] + 'create_new_model';
$("#mask").css({ display: "block", "z-index": "9999" });
$.ajax({
url: url_href,
type: "POST",
data: data,
success: function (res) {
backToModelListPage();
},
error: function (xhr) {
// 隐藏 loading
// 只有请求不正常(状态码不为200)才会执行
$(".ui.error.message").text(xhr.responseText);
$(".ui.error.message").show();
},
complete: function (xhr) {
$("#mask").css({ display: "none", "z-index": "1" });
},
});
}

function backToModelListPage() {
let url_href = location.href.split("create_online_model")[0] + 'show_model';
window.location.href = url_href;
}
window.submitSaveModel = submitSaveModel;
window.backToModelListPage = backToModelListPage;
})();
</script>

+ 25
- 3
templates/repo/modelmanage/index.tmpl View File

@@ -25,6 +25,23 @@
border-bottom-left-radius: 4px;
box-shadow: 0 2px 3px 0 rgb(34 36 38 / 15%);
}
.m-blue-btn {
background-color: rgb(22, 132, 252) !important;
}
.m-blue-btn:hover {
background-color: #66b1ff !important;
color: #fff;
}

.m-blue-btn:focus {
background-color: #66b1ff !important;
color: #fff;
}

.m-blue-btn:active {
background-color: #3a8ee6 !important;
color: #fff;
}
</style>
<link rel="stylesheet" href="/self/ztree/css/zTreeStyle/zTreeStyle.css" type="text/css">

@@ -57,8 +74,10 @@
</div>
<div class="column right aligned">
<!-- -->
<a class="ui button {{if .Permission.CanWrite $.UnitTypeModelManage}} blue m-blue-btn {{else}} disabled {{end}}"
href="{{.RepoLink}}/modelmanage/create_local_model_1">{{$.i18n.Tr "repo.model.manage.import_local_model"}}</a>
<a class="ui button {{if .Permission.CanWrite $.UnitTypeModelManage}} green {{else}} disabled {{end}}"
onclick="showcreate(this)">{{$.i18n.Tr "repo.model.manage.import_new_model"}}</a>
href="{{.RepoLink}}/modelmanage/create_online_model">{{$.i18n.Tr "repo.model.manage.import_online_model"}}</a>
</div>
</div>
{{if eq $.MODEL_COUNT 0}}
@@ -66,6 +85,7 @@
<div class="ui icon header bgtask-header-pic"></div>
<div class="bgtask-content-header">{{$.i18n.Tr "repo.model.manage.notcreatemodel"}}</div>
<div class="bgtask-content">
<!--
{{if $.RepoIsEmpty}}
<div class="bgtask-content-txt">{{$.i18n.Tr "repo.model.manage.init1"}}<a href="{{.RepoLink}}">{{$.i18n.Tr "repo.model.manage.init2"}}</a></div>
{{end}}
@@ -73,6 +93,8 @@
<div class="bgtask-content-txt">{{$.i18n.Tr "repo.model.manage.createtrainjob_tip"}}<a
href="{{.RepoLink}}/modelarts/train-job">&nbsp;{{$.i18n.Tr "repo.model.manage.createtrainjob"}}</a></div>
{{end}}
-->
<div class="bgtask-content-txt">{{$.i18n.Tr "repo.model.manage.createmodel_tip"}}<a href="{{.RepoLink}}/modelarts/train-job">&nbsp;{{$.i18n.Tr "repo.model.manage.createtrainjob"}}</a></div>
<div class="bgtask-content-txt">{{$.i18n.Tr "repo.platform_instructions1"}}<a href="https://git.openi.org.cn/zeizei/OpenI_Learning">&nbsp;{{$.i18n.Tr "repo.platform_instructions2"}}&nbsp;</a>{{$.i18n.Tr "repo.platform_instructions3"}}</div>

</div>
@@ -421,7 +443,8 @@
let train_html = '';
modelData = data;
for (let i = 0; i < n_length; i++) {
train_html += `<div class="item" data-value="${data[i].VersionName}">${data[i].VersionName}</div>`
var VersionName = data[i].VersionName || 'V0001';
train_html += `<div class="item" data-value="${VersionName}">${VersionName}</div>`
train_html += '</div>'
}
if (data.length) {
@@ -568,5 +591,4 @@
$("#choice_Engine").removeClass('disabled');
}
}
</script>

+ 5
- 528
templates/repo/modelmanage/showinfo.tmpl View File

@@ -1,533 +1,10 @@
{{template "base/head" .}}
<div class="repository">
<link rel="stylesheet" href="{{StaticUrlPrefix}}/css/vp-modelmanage-common-detail.css?v={{MD5 AppVer}}" />
<div class="repository release dataset-list view">
{{template "repo/header" .}}
<style>
.model_header_text{
font-size: 14px;
color: #101010;
font-weight: bold;
}
.ti_form{
text-align: left;
max-width: 100%;
vertical-align: middle;
}
.ti-text-form-label {
padding-bottom: 20px;
padding-right: 20px;
color: #8a8e99;
font-size: 14px;
white-space: nowrap !important;
width: 80px;
line-height: 30px;
}
.ti-text-form-content {
line-height: 30px;
padding-bottom: 20px;
width: 100%;
}
.change-version{
min-width: auto !important;
border: 1px solid rgba(187, 187, 187, 100) !important;
border-radius: .38571429rem !important;
margin-left: 1.5em;
}
.title-word-elipsis{
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width: 30%;
}
.word-elipsis{
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
padding-right: 80px;
}
.half-table{
width: 50%;
float: left;
}
.text-width80 {
width: 100px;
line-height: 30px;
}
.tableStyle{
width:100%;
table-layout: fixed;
}
.iword-elipsis{
display: inline-block;
width: 80%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>
<div class="ui container">
<h4 class="ui header" id="vertical-segment">
<!-- <a href="javascript:window.history.back();"><i class="arrow left icon"></i>返回</a> -->
<div class="ui breadcrumb">
<a class="section" href="{{$.RepoLink}}/modelmanage/show_model">
{{$.i18n.Tr "repo.model.manage.model_manage"}}
</a>
<div class="divider"> / </div>
<div class="active section">{{.name}}</div>
</div>
<select class="ui dropdown tiny change-version" id="dropdown" onchange="changeInfo(this.value)">
</select>
</h4>
<div id="showInfo" style="border:1px solid #e2e2e2;padding: 20px 60px;margin-top:24px">
<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>
<a class="item" data-tab="second">{{$.i18n.Tr "repo.model_download"}}</a>
</div>
<div class="ui tab active" data-tab="first">
<div class="half-table">
<span class="model_header_text">{{$.i18n.Tr "repo.model.manage.baseinfo"}}</span>
<table class="tableStyle" style="margin-top:20px;">
<tbody>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.model.manage.model_name"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="modelName" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.model.manage.version"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="version" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.migrate_items_labels"}}</td>
<td class="ti-text-form-content">
<div id="label" style="overflow: hidden;width: 95%;">
</div>
</td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.modelarts.model_size"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="size" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.modelarts.createtime"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="createTime" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.model.manage.description"}}</td>
<td class="ti-text-form-content" >
<div id="edit-td" style="display:flex">
<span id="description" title="" class="iword-elipsis"></span>
<i id="edit-pencil" data-id="" data-desc="" class="pencil alternate icon" style="cursor:pointer;vertical-align: top;" id="editor" onclick="editorFn(this)"></i>
</div>
</td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.modelarts.train_job"}}</td>
<td class="ti-text-form-content word-elipsis">
<a id="displayJobNameHref" class="title" style="font-size: 14px;" target="_blank">
<span id="displayJobName" class="fitted" style="width: 90%;vertical-align: middle;"></span>
</a>
</td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.modelarts.code_version"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="codeBranch" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.modelarts.train_job.start_file"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="bootFile" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.modelarts.train_job.train_dataset"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="datasetName" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.modelarts.train_job.run_parameter"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="parameters" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.modelarts.train_job.AI_Engine"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="engineName" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.modelarts.train_job.standard"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="flavorName" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.modelarts.train_job.compute_node"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="workServerNumber" title=""></span></td>
</tr>
</tbody>
</table>
</div>
<div class="half-table">
<span class="model_header_text">{{$.i18n.Tr "repo.model.manage.model_accuracy"}}</span>
<table class="tableStyle" style="margin-top:20px;">
<tbody>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.model.manage.Accuracy"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="Accuracy" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">F1</td>
<td class="ti-text-form-content word-elipsis"><span id="F1" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.model.manage.Precision"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="Precision" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.model.manage.Recall"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="Recall" title=""></span></td>
</tr>
</tbody>
</table>
</div>
<div style="clear: both;"></div>
</div>
<div class="ui tab" data-tab="second">
<input type="hidden" name="model" value="-1">
<input type="hidden" name="modelback" value="-1">
<div class='ui breadcrumb model_file_bread' id='file_breadcrumb'>
<div class="active section"></div>
<div class="divider"> / </div>
</div>
<div id="dir_list">
</div>
</div>
</div>
</div>
<div id="__vue-root"></div>
</div>
</div>
<script src="{{StaticUrlPrefix}}/js/vp-modelmanage-common-detail.js?v={{MD5 AppVer}}"></script>
{{template "base/footer" .}}
<script>
let url = location.href.split('show_model')[0]
let trainJobUrl =url.split('modelmanage')[0]
let ID = location.search.split('?name=').pop()
$(document).ready(function(){
$('.secondary.menu .item').tab();
});
$(document).ready(loadInfo);
function changeInfo(version){
$.get(`${url}show_model_info_api?name=${ID}`,(data)=>{
let versionData = data.filter((item)=>{
return item.version === version
})
let returnArray = []
returnArray = transObj(versionData)
let [initObj,initModelAcc,id] = returnArray
editorCancel('','')
renderInfo(initObj,initModelAcc,id)
loadModelFile(versionData[0].id,versionData[0].version,'','','init')
})
}
function loadInfo(){
$.get(`${url}show_model_info_api?name=${ID}`,(data)=>{
let html = ''
for (let i=0;i<data.length;i++){
if(!data[i].isCanOper){
$("#edit-pencil").css("display","none")
}
html += `<option value="${data[i].version}">${data[i].version}</option>`
}
$('#dropdown').append(html)
let returnArray = []
returnArray = transObj(data)
let [initObj,initModelAcc,id] = returnArray
renderInfo(initObj,initModelAcc,id)
loadModelFile(data[0].id,data[0].version,'','','init')
})
}
function getEngineName(model){
if(model.engine == 0){
return "PyTorch";
}else if(model.engine == 1 || model.engine == 121 || model.engine == 38){
return "TensorFlow";
}else if(model.engine == 2 || model.engine == 122 || model.engine == 35 || model.engine == 37){
return "MindSpore";
}else if(model.engine == 3){
return "Other";
}else if(model.engine == 4){
return "PaddlePaddle";
}else if(model.engine == 5){
return "OneFlow";
}else if(model.engine == 6){
return "MXNet";
}
else{
return "Other"
}
}
function transObj(data){
let {id,name,version,label,size,description,createdUnix,accuracy,codeBranch,codeCommitID,trainTaskInfo} = data[0]
let modelAcc = JSON.parse(accuracy)
trainTaskInfo = JSON.parse(trainTaskInfo)
let engineName = getEngineName(data[0])
parameters = JSON.parse(trainTaskInfo.Parameters)
parameters = parameters.parameter.length === 0 ? '--':parameters.parameter
size = tranSize(size)
let time = transTime(createdUnix)
let initObj = {
modelName:name || '--',
version:version,
label:label || '--',
size:size,
createTime:time,
description:description || '--',
codeBranch:codeBranch || '--',
codeCommitID:codeCommitID || '--',
bootFile:trainTaskInfo.BootFile || '--',
datasetName:trainTaskInfo.DatasetName || '--',
parameters:trainTaskInfo.Parameters || '--',
flavorName:trainTaskInfo.FlavorName || '--',
workServerNumber:trainTaskInfo.WorkServerNumber || '--',
parameters:parameters,
engineName:engineName,
displayJobName:trainTaskInfo.DisplayJobName || '--',
trainJobVersionName:trainTaskInfo.VersionName || '',
cloudBrainJobID:trainTaskInfo.JobID|| '',
cloudBrainType:trainTaskInfo.Type,
}
let initModelAcc = {
Accuracy: modelAcc.Accuracy || '--',
F1: modelAcc.F1 || '--',
Precision:modelAcc.Precision || '--',
Recall: modelAcc.Recall || '--'
}
return [initObj,initModelAcc,id]
}
function transTime(time){
let date = new Date(time * 1000);//时间戳为10位需*1000,时间戳为13位的话不需乘1000
let Y = date.getFullYear() + '-';
let M = (date.getMonth()+1 < 10 ? '0'+(date.getMonth()+1):date.getMonth()+1) + '-';
let D = (date.getDate()< 10 ? '0'+date.getDate():date.getDate())+ ' ';
let h = (date.getHours() < 10 ? '0'+date.getHours():date.getHours())+ ':';
let m = (date.getMinutes() < 10 ? '0'+date.getMinutes():date.getMinutes()) + ':';
let s = date.getSeconds() < 10 ? '0'+date.getSeconds():date.getSeconds();
return Y+M+D+h+m+s;
}
function tranSize(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(2);//保留的小数位数
return size+unitArr[index];
}
function editorFn(context){
let id= context.dataset.id
let text = context.dataset.desc
let textValue = text.replace(/enter;/g,'\r\n')
$('#edit-td').replaceWith(`<div id='edit-div' style='width:80%;display: inline-block;'><textarea id='textarea-value' value='' rows='3' maxlength='255' style='width:80%;white-space: nowrap;' id='edit-text'>${textValue}</textarea><i class='check icon' style='color: #50d4ab;' onclick='editorSure("${text}","${id}")'></i><i class='times icon' style='color: #f66f6a;' onclick='editorCancel("${text}","${id}")'></i></div>`);
}
function editorCancel(text,id){
let objkey = text.replace(/enter;/g,'\r\n')
$('#edit-div').replaceWith(`<div id="edit-td" style="display:flex;"><span id="Description" title="${objkey}" class="iword-elipsis">${objkey}</span><i id="edit-pencil" data-id="${id}" data-desc="${text}" class="pencil alternate icon" style="cursor:pointer;vertical-align: top;" id="editor" onclick="editorFn(this)"></div>`)
}
function editorSure(text,id){
let description=$('#textarea-value').val()
let sourcetext = $('#textarea-value').val().replace(/\n/g,'enter;')
let data = {
id:id,
description:description
}
$.ajax({
url:`${url}modify_model`,
type:'PUT',
data:data
}).done((res)=>{
$('#edit-div').replaceWith(`<div id="edit-td" style="display:flex;"><span id="Description" title="${description}" class="iword-elipsis">${description}</span><i id="edit-pencil" data-id="${id}" data-desc="${sourcetext}" class="pencil alternate icon" style="cursor:pointer;vertical-align: top;" id="editor" onclick="editorFn(this)"></div>`)
})
}
function renderInfo(obj,accObj,id){
for(let key in obj){
if(key==="description"){
let descriptionText=obj[key].replace(/\r\n|\n/g,'enter;')
$(`#${key}`).text(obj[key])
$(`#${key}`).attr("title",obj[key])
$('#edit-pencil').attr("data-id",id)
$('#edit-pencil').attr("data-desc",descriptionText)
}
else if(key==="label"){
$('#Label').empty()
if(obj[key]==='--'){
$('#Label').text(obj[key])
}else{
let labelArray = obj[key].trim().replace(/ +/g,' ').split(' ')
let html=''
for(let i=0;i<labelArray.length;i++){
html += `<a class="ui label" title="${labelArray[i]}">${labelArray[i]}</a>`
}
$('#Label').append(html)
}
}
else if(key==="codeCommitID"){
let codeCommit = obj[key].slice(0,10)
let html = `<a style="margin-left:1rem" class="ui label" title="${codeCommit}">${codeCommit}</a>`
$('#CodeBranch').append(html)

}
else if(key==="displayJobName"){
let type=obj["cloudBrainType"]
let href=""
if(type==1){
href=trainJobUrl + "modelarts/train-job/" + obj["cloudBrainJobID"]
}else if(type==0){
href=trainJobUrl + "cloudbrain/train-job/" + obj["cloudBrainJobID"]
}else if(type==2){
href=trainJobUrl + "grampus/train-job/" + obj["CloudBrainJobID"]
}
$(`#displayJobNameHref`).attr("href",href)
$(`#displayJobNameHref`).attr("title",obj[key])
$(`#${key}`).text(obj[key])

let versionName = obj["trainJobVersionName"]
if(versionName!=""){
let html = `<span style="margin-left:1rem" class="ui label">${versionName}</span>`
$('#displayJobName').append(html)
}
}
else if(key==="parameters"){
if(obj[key]==='--'){
$(`#${key}`).text(obj[key])
}else{
const parameterArray = obj[key].map(element => {
let labelValue = `${element.label}=${element.value}`
return labelValue
});
const parameter = parameterArray.join('; ')
$(`#${key}`).text(parameter)
$(`#${key}`).attr("title",parameter)
}
}
else{
$(`#${key}`).text(obj[key])
$(`#${key}`).attr("title",obj[key])
}
}
for(let key in accObj){
$(`#${key}`).text(accObj[key])
$(`#${key}`).attr("title",accObj[key])
}
}

function loadModelFile(ID,version_name,parents,filename,init){
$.get(`${url}query_onelevel_modelfile?ID=${ID}&parentDir=${parents}`, (data) => {
$('#dir_list').empty()
renderDir(data,ID,version_name)
if(init==="init"){
$('input[name=model]').val("")
$('input[name=modelback]').val(version_name)
$('#file_breadcrumb').empty()
let htmlBread = ""
htmlBread += `<div class='active section'>${version_name}</div>`
htmlBread += "<div class='divider'> / </div>"
$('#file_breadcrumb').append(htmlBread)
}else{
renderBrend(ID,version_name,parents,filename,init)
}
})
}
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(2);//保留的小数位数
return size+unitArr[index];
}

function renderBrend(ID,version_name,parents,filename,init){
if(init=="folder"){
let htmlBrend = ""
let sectionName=$('#file_breadcrumb .active.section').text()
let parents1 = $('input[name=model]').val()
let filename1 = $('input[name=modelback]').val()
if(parents1===""){
$('#file_breadcrumb .active.section').replaceWith(`<a class='section' onclick="loadModelFile('${ID}','${version_name}','${parents1}','','init')">${sectionName}</a>`)
}else{
$('#file_breadcrumb .active.section').replaceWith(`<a class='section' onclick="loadModelFile('${ID}','${version_name}','${parents1}','${filename1}')">${sectionName}</a>`)
}
htmlBrend += `<div class='active section'>${filename}</div>`
htmlBrend += "<div class='divider'> / </div>"
$('#file_breadcrumb').append(htmlBrend)
$('input[name=model]').val(parents)
$('input[name=modelback]').val(filename)
}else{
$('input[name=model]').val(parents)
$('input[name=modelback]').val(filename)
let selectEle = $('#file_breadcrumb a.section').filter(
(index, item) => {
return item.text == filename;
}
);
selectEle.nextAll().remove();
selectEle.after("<div class='divider'> / </div>");
selectEle.replaceWith(`<div class='active section'>${filename}</div>`);
}
}
function renderDir(data,ID,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>'
for(let i=0;i<data.length;i++){
let dirs_size = renderSize(data[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[i].IsDir){
html += `<a onclick="loadModelFile('${ID}','${version_name}','${data[i].ParenDir}','${data[i].FileName}','folder')">`
html += "<span class='fitted'><i class='folder icon' width='16' height='16' aria-hidden='true'></i>" + data[i].FileName + "</span>"
}else{
html += `<a href="${url}${ID}/downloadsingle?parentDir=${data[i].ParenDir}&fileName=${data[i].FileName}">`
html += "<span class='fitted'><i class='file icon' width='16' height='16' aria-hidden='true'></i>" + data[i].FileName + "</span>"
}
html += '</a>'
html += "</span>"
html += "</td>"
html += "<td class='message seven wide'>"
if(data[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[i].ModTime + "</span>"
html += "</td>"
html += "</tr>"
}
html += "</tbody>"
html += "</table>"
html += "</div>"
html += "</div>"
html += "</div>"
html += "</div>"
$('#dir_list').append(html)
}
</script>

+ 2
- 1
templates/repo/modelsafety/show.tmpl View File

@@ -861,7 +861,8 @@
$('td.ti-text-form-content.spec div').text(specStr);
SPEC && $('td.ti-text-form-content.resorce_type div').text(getListValueWithKey(ACC_CARD_TYPE, SPEC.AccCardType));
}
var oLogHref = $('#-log-down').attr('href');
var repoPath = {{$.RepoRelPath}};
var oLogHref = `/api/v1/repos/${repoPath}/cloudbrain`;
$('#-log-down').attr('href', oLogHref + `/${res.ID}/download_log_file`);
$('.full-log-dialog').attr('data-href', oLogHref + `/${res.ID}/download_log_file`);
if (res.ResultJson) {


+ 7
- 7
templates/user/dashboard/cloudbrains.tmpl View File

@@ -65,7 +65,7 @@
</div>
</div>
</div>
{{range .Tasks}}
{{range .Tasks}}
{{if .Repo}}
<div class="ui grid stackable item">
<div class="row">
@@ -155,7 +155,7 @@
<!-- 智算中心 -->
<div class="one wide column text center nowrap" style="width:8% !important;">
<span style="font-size: 12px;" class="aicenter_{{.DisplayJobName}}_{{$JobID}}">{{if .AiCenter}}{{.AiCenter}}{{else}}--{{end}}</span>
<span style="font-size: 12px;" class="aicenter_{{.DisplayJobName}}_{{$JobID}}" title="{{if .AiCenter}}{{.AiCenter}}{{else}}--{{end}}">{{if .AiCenter}}{{.AiCenter}}{{else}}--{{end}}</span>
</div>
<!-- XPU类型 -->
<div class="one wide column text center nowrap" style="width:10% !important;">
@@ -169,16 +169,16 @@
spanEl.setAttribute('title', cardType);
spanEl.innerText = cardType;
var cluster = spec.Cluster || '--';
var cluster = {{.Cluster}} || '--';
var clusterName = document.querySelector('.cloudbrain_debug').dataset['cluster' + cluster[0] + cluster.toLocaleLowerCase().slice(1)] || '--';
spanEl = document.querySelector('.cluster_{{.DisplayJobName}}_{{$JobID}}');
spanEl.setAttribute('title', cluster);
spanEl.innerText = clusterName;

var aiCenter = spec.AiCenterName || '--';
spanEl = document.querySelector('.aicenter_{{.DisplayJobName}}_{{$JobID}}');
spanEl.setAttribute('title', aiCenter);
spanEl.innerText = aiCenter;
// var aiCenter = spec.AiCenterName || '--';
// spanEl = document.querySelector('.aicenter_{{.DisplayJobName}}_{{$JobID}}');
// spanEl.setAttribute('title', aiCenter);
// spanEl.innerText = aiCenter;
})();
</script>
<!-- 项目 -->


+ 52
- 19
web_src/js/components/Model.vue View File

@@ -16,16 +16,17 @@
prop="name"
:label="i18n.model_name"
align="left"
min-width="17%"
min-width="20%"
>
<template slot-scope="scope">
<div class="expand-icon" v-if="scope.row.hasChildren === false">
<i class="el-icon-arrow-right"></i>
</div>
<!-- <i class="el-icon-time"></i> -->
<span v-if="!scope.row.Children" :class="scope.row.modelType == '1' ? 'm-local' : 'm-online'">{{ scope.row.modelType == '1' ? i18n.local : i18n.online }}</span>
<a
class="text-over"
:href="showinfoHref + scope.row.name"
:href="showinfoHref + encodeURIComponent(scope.row.name)"
:title="scope.row.name"
>{{ scope.row.name }}</a
>
@@ -131,12 +132,12 @@

<el-table-column
:label="i18n.model_operation"
min-width="17%"
min-width="15%"
align="center"
>
<template slot-scope="scope">
<div class="space-around">
<a
<div class="space-around" >
<!--<a
:style="{
visibility: !scope.row.Children ? 'visible' : 'hidden',
}"
@@ -149,19 +150,23 @@
)
"
>{{ i18n.model_create_new_ver }}</a
>
<a
>-->
<a class="op-btn"
v-show="scope.row.modelType == 1"
:href="url + 'create_local_model_1?type=1&name=' + encodeURIComponent(scope.row.name) + '&id=' + scope.row.id"
:class="{ disabled: !scope.row.isCanOper }"
>{{ i18n.modify }}</a>
<a class="op-btn" v-show="scope.row.modelType != 1" style="color:transparent;cursor:default;" >{{ i18n.modify }}</a>
<a class="op-btn"
:href="loadhref + scope.row.id"
:class="{ disabled: !scope.row.isCanOper }"
>{{ i18n.model_download }}</a
>
<a
>{{ i18n.model_download }}</a>
<a class="op-btn"
:class="{ disabled: !scope.row.isCanDelete }"
@click="
deleteModel(scope.row.id, scope.row.cName, scope.row.rowKey)
"
>{{ i18n.model_delete }}</a
>
>{{ i18n.model_delete }}</a>
</div>
</template>
</el-table-column>
@@ -223,9 +228,10 @@ export default {
let tableData;
tableData = res.data;
for (let i = 0; i < tableData.length; i++) {
trainTaskInfo = JSON.parse(tableData[i].trainTaskInfo);
trainTaskInfo = JSON.parse(tableData[i].trainTaskInfo || '{}');
tableData[i].engineName = this.getEngineName(tableData[i]);
tableData[i].computeResource = trainTaskInfo.ComputeResource;
// tableData[i].computeResource = trainTaskInfo.ComputeResource;
tableData[i].computeResource = tableData[i].type == '0' ? 'CPU/GPU' : 'NPU';
tableData[i].cName = tableData[i].name;
tableData[i].rowKey = tableData[i].id + Math.random();
tableData[i].name = "";
@@ -474,7 +480,7 @@ export default {
try {
this.loadNodeMap.clear();
this.$axios
.get(location.href + "_api", {
.get(this.url + "show_model_api", {
params: this.params,
})
.then((res) => {
@@ -483,15 +489,15 @@ export default {
let trainTaskInfo;
this.tableData = res.data.data;
for (let i = 0; i < this.tableData.length; i++) {
trainTaskInfo = JSON.parse(this.tableData[i].trainTaskInfo);
trainTaskInfo = JSON.parse(this.tableData[i].trainTaskInfo || '{}');
this.tableData[i].cName = this.tableData[i].name;
this.tableData[i].rowKey = this.tableData[i].id + Math.random();
this.tableData[i].engineName = this.getEngineName(
this.tableData[i]
);
this.tableData[i].computeResource = trainTaskInfo.ComputeResource;
this.tableData[i].hasChildren =
res.data.data[i].versionCount === 1 ? false : true;
// this.tableData[i].computeResource = trainTaskInfo.ComputeResource;
this.tableData[i].computeResource = this.tableData[i].type == '0' ? 'CPU/GPU' : 'NPU';
this.tableData[i].hasChildren = res.data.data[i].versionCount === 1 ? false : true;
if (this.tableData[i].status !== 1) {
countStatus++;
}
@@ -615,6 +621,24 @@ export default {
white-space: nowrap;
}

.m-local {
background-color: rgb(22, 132, 252);
color: white;
padding: 2px 3px;
border-radius: 4px;
font-size: 12px;
margin-right: 2px;
}

.m-online {
background-color: rgb(91, 185, 115);
color: white;
padding: 2px 3px;
border-radius: 4px;
font-size: 12px;
margin-right: 2px;
}

.el-icon-arrow-right {
font-family: element-icons !important;
speak: none;
@@ -677,6 +701,15 @@ export default {
justify-content: space-around;
}

.op-btn-c {
text-align: right;
padding-right: 20px;
}

.op-btn {
margin: 0 0 0 5px;
}

.disabled {
cursor: default;
pointer-events: none;


+ 1
- 1
web_src/js/components/basic/editDialog.vue View File

@@ -1,6 +1,6 @@
<template>

<el-dialog :close-on-click-modal="!deleteLoading" v-dlg-drag :title="dialogTitle" :visible.sync="deleteDialog">
<el-dialog :close-on-click-modal="!deleteLoading" :title="dialogTitle" :visible.sync="deleteDialog">
<div class="message-box__content">


+ 1
- 1
web_src/js/features/cloudrbanin.js View File

@@ -411,7 +411,7 @@ export default async function initCloudrain() {
$(`#${jobName}`).popup("toggle");
} else {
let versionData = data.filter((item) => {
return item.Version === versionName;
return item.version === versionName;
});
if (versionData.length == 0) {
$(`#${jobName}`).popup("toggle");


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

@@ -105,6 +105,9 @@ export const i18nVue = {
file_sync_fail:"文件同步失败",
no_file_to_download:"没有文件可以下载",
task_not_finished:"任务还未结束,稍后再来看看",
local:"本地",
online:"线上",
modify:"修改",
},
US: {
computer_vision: "computer vision",
@@ -216,5 +219,8 @@ export const i18nVue = {
file_sync_fail:"File synchronization failed",
no_file_to_download:"No files can be downloaded",
task_not_finished:"Task not finished yet, please wait",
local:"Local",
online:"Online",
modify:"Modify",
},
};

+ 11
- 10
web_src/js/index.js View File

@@ -6,8 +6,10 @@ import "./publicpath.js";
import "./polyfills.js";
import "./features/letteravatar.js";
import Vue from "vue";
import ElementUI from "element-ui";
import "element-ui/lib/theme-chalk/index.css";
import localeEn from 'element-ui/lib/locale/lang/en';
import localeZh from 'element-ui/lib/locale/lang/zh-CN';
import ElementUI from "element-ui";
import axios from "axios";
import qs from "qs";
import Cookies from "js-cookie";
@@ -56,15 +58,19 @@ import './features/ad.js';
import { Fancybox } from "./vendor/fancybox.esm.js";


Vue.use(ElementUI);
Vue.prototype.$axios = axios;
Vue.prototype.$Cookies = Cookies;
Vue.prototype.qs = qs;
Vue.prototype.$message = Message;
Vue.prototype.$locale = i18nVue;
window.i18n = i18nVue[document.querySelector('html').getAttribute('lang') == 'zh-CN' ? 'CN' : 'US'];
const lang = document.querySelector('html').getAttribute('lang');
window.i18n = i18nVue[lang == 'zh-CN' ? 'CN' : 'US'];
const { AppSubUrl, StaticUrlPrefix, csrf } = window.config;

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

Object.defineProperty(Vue.prototype, "$echarts", {
value: echarts,
});
@@ -5071,12 +5077,7 @@ function initcreateRepo() {
initcreateRepo();

function initChartsNpu() {
const url = window.location.href;
const urlArr = url.split("/");
let userName = urlArr.slice(-5)[0];
let repoPath = urlArr.slice(-4)[0];
let jobID = urlArr.slice(-1)[0];

const repoPath = $('.metric_chart').data('path')
let options = {
legend: {
data: [],
@@ -5127,7 +5128,7 @@ function initChartsNpu() {
document.getElementById(`metric-${versionName}`)
);
$.get(
`${window.config.AppSubUrl}/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/metric_statistics?version_name=${versionName}&statistic_type=each&metrics=`,
`${window.config.AppSubUrl}/api/v1/repos/${repoPath}`,
(res) => {
let filterDta = res.MetricsInfo.filter((item) => {
return ![


+ 106
- 0
web_src/vuepages/apis/modules/modelmanage.js View File

@@ -0,0 +1,106 @@
import service from "../service";
import Qs from 'qs';

// 保存本地模型
export const saveLocalModel = (data) => {
return service({
url: `${data.repo}/modelmanage/create_local_model`,
method: 'post',
headers: { 'Content-type': 'application/x-www-form-urlencoded' },
params: {},
data: Qs.stringify(data),
});
};

// 修改模型
// data: {id,type,name,version,engine,label,description:}
export const modifyModel = (data) => {
return service({
url: `${data.repo}/modelmanage/modify_model`,
method: 'put',
headers: { 'Content-type': 'application/x-www-form-urlencoded' },
params: {},
data: Qs.stringify(data),
});
};

// 求模型信息
export const getModelInfoByName = (params) => {
return service({
url: `${params.repo}/modelmanage/show_model_info_api`,
method: 'get',
params,
data: {},
});
};

// 求模型中文件列表
// params {repo, ID, parentDir}
export const getModelFiles = (params) => {
return service({
url: `${params.repo}/modelmanage/query_onelevel_modelfile`,
method: 'get',
params,
data: {},
});
};

// 删除模型文件
// params {repo, id, fileName}
export const deleteModelFile = (params) => {
return service({
url: `${params.repo}/modelmanage/delete_model_file`,
method: 'delete',
params,
data: {},
});
};

/* 文件上传相关 */
// 上传文件1: 获取文件chunks信息
// params: { md5, type: 0-CPU/GPU,1-NPU, file_name, scene: 'model', modeluuid }
// return: uploadID, uuid, uploaded, chunks, attachID, modeluuid, modelName, fileName
export const getChunks = (params) => {
return service({
url: `/attachments/model/get_chunks`,
method: 'get',
params,
data: {},
});
};

// 上传文件2: 上传新文件
// params: { totalChunkCounts, md5, size, fileType, type, file_name, scene=model, modeluuid=xxxx }
// return: uploadID, uuid
export const getNewMultipart = (params) => {
return service({
url: `/attachments/model/new_multipart`,
method: 'get',
params,
data: {},
});
};

// 上传文件3: 获取分片上传地址
// params: { uuid, uploadID, size, chunkNumber, type, file_name, scene=model }
// return: url
export const getMultipartUrl = (params) => {
return service({
url: `/attachments/model/get_multipart_url`,
method: 'get',
params,
data: {},
});
};

// 上传文件4: 完成上传后
// data: { uuid, uploadID, size, type, file_name, dataset_id, description, scene=model, modeluuid=xxxx }
export const setCompleteMultipart = (data) => {
return service({
url: `/attachments/model/complete_multipart`,
method: 'post',
headers: { 'Content-type': 'application/x-www-form-urlencoded' },
params: {},
data: Qs.stringify(data),
});
};

+ 13
- 0
web_src/vuepages/apis/modules/resources.js View File

@@ -110,6 +110,19 @@ export const getResSpecificationList = (params) => {
});
}

// 查询资源规格列表(所有)
// cluster 所属集群 :OpenI 启智集群,C2Net 智算集群
// queue 所属队列id
// status 状态 : 1 待审核 2已上架 3已下架
export const getResSpecificationListAll = (params) => {
return service({
url: '/admin/resources/specification/list/all',
method: 'get',
params,
data: {},
});
}

// 同步智算网络资源池(队列)
export const syncResSpecification = () => {
return service({


+ 3
- 0
web_src/vuepages/const/index.js View File

@@ -14,3 +14,6 @@ export const AI_CENTER = [{ k: 'OpenIOne', v: i18n.t('resourcesManagement.OpenIO
export const COMPUTER_RESOURCES = [{ k: 'GPU', v: 'GPU' }, { k: 'NPU', v: 'NPU' }, { k: 'MLU', v: 'MLU' }];
export const ACC_CARD_TYPE = [{ k: 'T4', v: 'T4' }, { k: 'A100', v: 'A100' }, { k: 'V100', v: 'V100' }, { k: 'ASCEND910', v: 'Ascend 910' }, { k: 'MLU270', v: 'MLU270' }, { k: 'RTX3080', v: 'RTX3080' }];
export const SPECIFICATION_STATUS = [{ k: '1', v: i18n.t('resourcesManagement.willOnShelf') }, { k: '2', v: i18n.t('resourcesManagement.onShelf') }, { k: '3', v: i18n.t('resourcesManagement.offShelf') }];

// 模型
export const MODEL_ENGINES = [{ k: '0', v: 'PyTorch' }, { k: '1', v: 'TensorFlow' }, { k: '2', v: 'MindSpore' }, { k: '4', v: 'PaddlePaddle' }, { k: '5', v: 'OneFlow' }, { k: '6', v: 'MXNet' }, { k: '3', v: 'Other' }];

+ 64
- 3
web_src/vuepages/langs/config/en-US.js View File

@@ -157,7 +157,7 @@ const en = {
computeCluster: 'Compute Cluster',
resourceSpecification: 'Resource Specification',
lastUpdateTime: 'Last Update Time',
resSceneDeleteConfirm: 'Are you sure to delete the current Resource Scene?',
resSceneDeleteConfirm: 'Are you sure to delete the current Resource Scene?',
resourceSpecificationIsAvailable: 'Specification Is Available',
resourceSpecificationIsAvailableAll: 'Specification Is Available(All)',
available: 'Available',
@@ -187,7 +187,7 @@ const en = {
onlyFace:'Only face',
onlyLicensePlate:'Only license plate',
dragThePictureHere:'Drag the picture here',
or:'or',
or:' or ',
clickUpload:'Click upload',
dataDesensitizationModelExperience:'Data desensitization model experience',
dataDesensitizationModelDesc:'Use AI technology to desensitize the face and license plate number in the picture. For more information about this model, please visit the project',
@@ -219,7 +219,68 @@ const en = {
graphicMemory: "Graphic Memory",
memory: "Memory",
sharedMemory: "Shared Memory",
tips:'The newly created debugging task will be placed in the project openi-notebook under your name. If there is no such project, the system will automatically create a new one.'
tips: 'The newly created debugging task will be placed in the project openi-notebook under your name. If there is no such project, the system will automatically create a new one.'
},
modelManage: {
modelManage: 'Model management',
modelName: 'Model name',
useCluster: 'Available clusters',
local: 'Local',
online: 'Online',
createModel: 'Create Model',
importLocalModel: 'Import Lacal Model',
importOnlineModel: 'Import Online Model',
modifyModelInfo: 'Modify model information',
addModelFiles: 'Add model files',
uploadModelFiles: 'Upload model files',
pleaseInputModelName: 'Please input model name',
version: 'Version',
modelEngine: 'Model engine',
modelLabel: 'Model label',
modelLabelInputTips: 'Input labels, multiple labels are separated by spaces',
modelDescr: 'Model description',
modelDescrInputTips: 'The description should not exceed 256 characters',
confirm: 'Confirm',
cancel: 'Cancel',
modelCreateFailed: 'Model create failed',
modelModifyFailed: 'Model modify failed',
fileUpload: 'File upload',
upload: 'Upload',
uploadStatus: 'Upload status',
modelFileUploadDefaultTips: 'Click to add files or drag files here directly',
modelFileUploadErrTips: 'Up to 10 files can be uploaded at a time, and the total file size of the model does not exceed {size}GB',
modelFileNameTips: 'The file name should not exceed 128 characters',
fileIstoBig: 'File is to big',
removeFile: 'Rmove file',
uploadSuccess: 'upload success',
uploadFailed: 'upload failed',
calcFileMd5: 'Calculating file MD5...',
uploading: 'Uploading...',
fileHasAlreadyInTheModel: 'This file has already in the model: ',
basicInfo: 'Basic information',
modelSize: 'Model size',
descr: 'Description',
createTime: 'Create Time',
label: 'Label',
trainTaskInfo: 'Train task information',
trainTask: 'Train task',
codeBranch: 'Code branch',
bootFile: 'Boot file',
trainDataset: 'Train dataset',
specInfo: 'Specifications',
workServerNumber: 'Amount of compute node',
runParameters: 'Run parameters',
seeMore: 'View more',
collapseDetails: 'Collapse details',
modelFilesList: 'Mode files list',
fileName: 'File name',
fileSize: 'File size',
updateTime: 'Upate Time',
operate: 'Operation',
delete: 'Delete',
infoModificationFailed: 'Information modify failed',
deleteModelFileConfirmTips: 'Are you sure you want to delete the current model file?',
modelFileDeleteFailed: 'Model file delete failed',
},
}



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

@@ -222,6 +222,69 @@ const zh = {
sharedMemory: "共享内存",
tips:'本次新建的调试任务会放在您名下项目openi-notebook中,如果没有该项目系统会自动新建一个。'
},
modelManage: {
modelManage: '模型管理',
modelName: '模型名称',
useCluster: '可用集群',
local: '本地',
online: '线上',
createModel: '创建模型',
importLocalModel: '导入本地模型',
importOnlineModel: '导入线上模型',
modifyModelInfo: '修改模型信息',
addModelFiles: '增加模型文件',
uploadModelFiles: '上传模型文件',
pleaseInputModelName: '请输入模型名称',
version: '版本',
modelEngine: '模型框架',
modelLabel: '模型标签',
modelLabelInputTips: '输入标签,多个标签用空格区分',
modelDescr: '模型描述',
modelDescrInputTips: '描述字数不超过255个字符',
confirm: '确定',
cancel: '取消',
modelCreateFailed: '模型创建失败',
modelModifyFailed: '模型修改失败',
fileUpload: '文件上传',
upload: '上传',
uploadStatus: '上传状态',
modelFileUploadDefaultTips: '点击添加文件或直接拖拽文件到此处',
modelFileUploadErrTips: '单次最多上传10个文件,模型总文件大小不超过{size}G',
modelFileNameTips: '文件名长度不超过128个字符',
fileIstoBig: '文件太大',
removeFile: '移除文件',
uploadSuccess: '上传成功',
uploadFailed: '上传失败',
calcFileMd5: '计算文件MD5...',
uploading: '上传中...',
fileHasAlreadyInTheModel: '该文件已上传在模型:',
basicInfo: '基本信息',
modelSize: '模型大小',
descr: '描述',
createTime: '创建时间',
label: '标签',
trainTaskInfo: '训练相关信息',
trainTask: '训练任务',
codeBranch: '代码分支',
bootFile: '启动文件',
trainDataset: '训练数据集',
specInfo: '规格',
workServerNumber: '计算节点',
runParameters: '运行参数',
seeMore: '查看更多信息',
collapseDetails: '折叠详细信息',
modelFilesList: '模型文件列表',
fileName: '文件名称',
fileSize: '文件大小',
updateTime: '更新时间',
operate: '操作',
delete: '删除',
infoModificationFailed: '信息修改失败',
deleteModelFileConfirmTips: '请确认是否删除当前模型文件?',
modelFileDeleteFailed: '模型文件删除失败',
},
};



export default zh;

+ 3
- 5
web_src/vuepages/pages/model/tuomin/index.vue View File

@@ -33,11 +33,9 @@
drag
>
<div class="el-upload__text">
{{ $t("dragThePictureHere")
}}<span style="color: rgba(136, 136, 136, 0.87)">{{
$t("or")
}}</span
>{{ $t("clickUpload") }}
<span>
<span>{{ $t("dragThePictureHere") }}</span><span style="color: rgba(136, 136, 136, 0.87)">{{ $t("or") }}</span><span>{{ $t("clickUpload") }}</span>
</span>
</div>
</el-upload>



+ 706
- 0
web_src/vuepages/pages/modelmanage/common/modelmanage-common-detail.vue View File

@@ -0,0 +1,706 @@
<template>
<div>
<div class="ui header">
<div class="ui breadcrumb">
<a class="section" :href="`${repo}/modelmanage/show_model`">{{ $t('modelManage.modelManage') }}</a>
<div class="divider"> / </div>
<div class="active section">{{ this.state.name }}</div>
</div>
<div class="version">
<el-select v-model="curVersion" @change="changeVersion" placeholder="">
<el-option v-for="item in modelList" :value="item.version" :key="item.version" :label="item.version">
</el-option>
</el-select>
</div>
</div>
<div class="content">
<div class="detail-info">
<div class="title">{{ $t('modelManage.basicInfo') }}:</div>
<div class="area-c">
<div class="area">
<div class="row">
<div class="tit">{{ $t('modelManage.useCluster') }}:</div>
<div class="val">
<div class="txt-wrap" :title="state.typeStr">
{{ state.typeStr }}
</div>
</div>
</div>
<div class="row">
<div class="tit">{{ $t('modelManage.modelSize') }}:</div>
<div class="val">
<div class="txt-wrap" :title="state.modelSize">{{ state.modelSize }}</div>
</div>
</div>
<div class="row" :class="isEidtDescr ? 'edit-row' : ''">
<div class="tit">{{ $t('modelManage.descr') }}:</div>
<div class="val" :class="isEidtDescr ? 'edit-val' : ''">
<div v-if="!isEidtDescr" class="txt-wrap" :title="state.description"
style="max-width:100%;width:unset;padding-right:20px;">
<span>{{ state.description }}</span>
<i v-if="canOperate" style="position:absolute;right:0;top:3px;color:rgb(22, 132, 252);cursor:pointer;"
class="el-icon-edit" @click="editDescr = state._description; isEidtDescr = true;"></i>
</div>
<div class="txt-edit" v-if="isEidtDescr">
<el-input type="textarea" v-model="editDescr" :maxLength="255"
:placeholder="$t('modelManage.modelDescrInputTips')"></el-input>
<i style="position:absolute;right:-4px;bottom:20px;color:rgb(255, 37, 37);cursor:pointer;"
class="icon times" @click="isEidtDescr = false;"></i>
<i style="position:absolute;right:-5px;bottom:2px;color:rgb(39, 177, 72);cursor:pointer;"
@click="submitEidt('descr')" class="icon check"></i>
</div>
</div>
</div>
</div>
<div class="area">
<div class="row">
<div class="tit">{{ $t('modelManage.modelEngine') }}:</div>
<div class="val">
<div class="txt-wrap" :title="state.engineName">{{ state.engineName }}</div>
</div>
</div>
<div class="row">
<div class="tit">{{ $t('modelManage.createTime') }}:</div>
<div class="val">
<div class="txt-wrap" :title="state.createTime">{{ state.createTime }}</div>
</div>
</div>
<div class="row" :class="isEidtLabel ? 'edit-row' : ''">
<div class="tit">{{ $t('modelManage.label') }}:</div>
<div class="val" :class="isEidtLabel ? 'edit-val' : ''">
<div v-if="!isEidtLabel" class="txt-wrap" :title="state.label"
style="max-width:100%;width:unset;padding-right:20px;">
<span>{{ state.label }}</span>
<i v-if="canOperate" style="position:absolute;right:0;top:3px;color:rgb(22, 132, 252);cursor:pointer;"
class="el-icon-edit" @click="editLabel = state._label; isEidtLabel = true;"></i>
</div>
<div class="txt-edit" v-if="isEidtLabel">
<el-input v-model="editLabel" :maxLength="255" :placeholder="$t('modelManage.modelLabelInputTips')"
@input="labelInput"></el-input>
<i style="position:absolute;right:-5px;bottom:20px;color:rgb(255, 37, 37);cursor:pointer;"
class="icon times" @click="isEidtLabel = false;"></i>
<i style="position:absolute;right:-5px;bottom:2px;color:rgb(39, 177, 72);cursor:pointer;"
@click="submitEidt('label')" class="icon check"></i>
</div>
</div>
</div>
</div>
</div>
<div v-show="isExpanded" style="margin-top:8px;" class="title">{{ $t('modelManage.trainTaskInfo') }}:</div>
<div v-show="isExpanded" class="area-c">
<div class="area">
<div class="row">
<div class="tit">{{ $t('modelManage.trainTask') }}:</div>
<div class="val">
<div class="txt-wrap" v-html="state.displayJobName"></div>
</div>
</div>
<div class="row">
<div class="tit">{{ $t('modelManage.codeBranch') }}:</div>
<div class="val">
<div class="txt-wrap" v-html="state.branchName"></div>
</div>
</div>
<div class="row">
<div class="tit">{{ $t('modelManage.bootFile') }}:</div>
<div class="val">
<div class="txt-wrap" :title="state.bootFile">{{ state.bootFile }}</div>
</div>
</div>
<div class="row">
<div class="tit">{{ $t('modelManage.trainDataset') }}:</div>
<div class="val">
<div class="txt-wrap" :title="state.datasetName">{{ state.datasetName }}</div>
</div>
</div>
</div>
<div class="area">
<div class="row">
<div class="tit">{{ $t('modelManage.specInfo') }}:</div>
<div class="val">
<div class="txt-wrap" :title="state.specStr">{{ state.specStr }}</div>
</div>
</div>
<div class="row">
<div class="tit">{{ $t('modelManage.workServerNumber') }}:</div>
<div class="val">
<div class="txt-wrap" :title="state.workServerNumber">{{ state.workServerNumber }}</div>
</div>
</div>
<div class="row">
<div class="tit">{{ $t('modelManage.runParameters') }}:</div>
<div class="val">
<div class="txt-wrap" :title="state.parameters">{{ state.parameters }}</div>
</div>
</div>
</div>
</div>
</div>
<div class="expand-line">
<div class="line"></div>
<div class="expand-btn" @click="isExpanded = !isExpanded">
<i class="icon chevron circle down" :class="isExpanded ? 'up' : ''"></i>
<span>{{ isExpanded ? $t('modelManage.collapseDetails') : $t('modelManage.seeMore') }}</span>
</div>
<div class="line"></div>
</div>
<div class="files-info">
<div class="top">
<div style="width:100%;margin-right:20px;">
<div class="title">{{ $t('modelManage.modelFilesList') }}:</div>
<div class="title files-path-c" style="margin-top:8px;margin-bottom:4px">
<div class="file-path" v-for="(item, index) in filePath">
<span v-if="index == filePath.length - 1" class="path-name">{{ item.label }}</span>
<a v-if="index != filePath.length - 1" class="path-name canback" @click="goBackDir(item)">{{ item.label
}}</a>
<span style="color:rgba(0,0,0,.4);" class="divider"> / </span>
</div>
</div>
</div>
<div>
<el-button v-if="modelType == 1 && canOperate" type="primary" icon="el-icon-upload" @click="goUploadPage">
{{ $t('modelManage.uploadModelFiles') }}
</el-button>
</div>
</div>
<div class="table-container">
<el-table ref="tableRef" :data="filesList" row-key="sn" style="width: 100%" v-loading="loading" stripe>
<el-table-column column-key="FileName" prop="FileName" sortable
:sort-method="(a, b) => a.FileName.toLocaleLowerCase().localeCompare(b.FileName.toLocaleLowerCase())"
:label="$t('modelManage.fileName')" align="left" header-align="left">
<template slot-scope="scope">
<div class="tbl-file-name">
<a v-if="scope.row.IsDir" @click="goNextDir(scope.row)" href="javascript:;">
<div class="fitted" :title="scope.row.FileName">
<i class="icon folder" width="16" height="16" aria-hidden="true"></i>
<span>{{ scope.row.FileName }}</span>
</div>
</a>
<a v-else :class="!canOperate ? 'disabled-download' : ''"
:href="canOperate ? `${repo}/modelmanage/${state.id}/downloadsingle?parentDir=${filePath.length > 1 ? encodeURIComponent(filePath.map(item => item.path).join('/').slice(1) + '/') : ''}&fileName=${scope.row.FileName}` : 'javascript:;'">
<div class="fitted" :title="scope.row.FileName">
<i class="icon file" width="16" height="16" aria-hidden="true"></i>
<span>{{ scope.row.FileName }}</span>
</div>
</a>
</div>
</template>
</el-table-column>
<el-table-column column-key="SizeShow" prop="SizeShow" sortable :sort-method="(a, b) => a.Size - b.Size"
:label="$t('modelManage.fileSize')" align="center" header-align="center" width="200">
</el-table-column>
<el-table-column column-key="ModTime" prop="ModTime" sortable
:sort-method="(a, b) => a.ModTimeNum - b.ModTimeNum" :label="$t('modelManage.updateTime')" align="center"
header-align="center" width="200">
</el-table-column>
<el-table-column v-if="modelType == 1 && canDelete" column-key="operate" prop="operate"
:label="$t('modelManage.operate')" align="center" header-align="center" width="200">
<template slot-scope="scope">
<span v-if="!scope.row.IsDir" class="btn-del" @click="deleteFile(scope.row)">{{ $t('modelManage.delete')
}}</span>
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>
</div>
</template>

<script>

import { getModelInfoByName, modifyModel, getModelFiles, deleteModelFile } from '~/apis/modules/modelmanage';
import { getUrlSearchParams, getListValueWithKey, transFileSize, renderSpecStr } from '~/utils';
import { MODEL_ENGINES } from '~/const';
import { formatDate } from 'element-ui/lib/utils/date-util';

const REPO_NAME = location.pathname.split('/')[2];
const MAX_LABEL_COUNT = 5;

export default {
data() {
return {
modelType: '0', // 1-本地, 0-线上
canOperate: false,
canDelete: false,
isExpanded: false,
loading: false,
repo: location.pathname.split('/').slice(0, 3).join('/'),
state: {
type: 0,
id: '',
name: '',
version: '0.0.1',
engine: '0',
label: '',
description: '',
},
editDescr: '',
isEidtDescr: false,
editLabel: '',
isEidtLabel: false,
engineList: MODEL_ENGINES,
curVersion: '',
modelList: [],
filesList: [],
filePath: [],
};
},
components: {},
methods: {
getDirFiles(dir) {
dir = dir.length ? dir.slice(1) : '';
getModelFiles({
repo: this.repo,
ID: this.state.id,
parentDir: dir,
}).then(res => {
const list = res.data || [];
list.forEach(item => {
item.SizeShow = item.IsDir ? '' : transFileSize(item.Size);
item.ModTimeNum = new Date(item.ModTime).getTime();
})
list.sort((a, b) => b.ModTimeNum - a.ModTimeNum);
this.filesList = list;
this.$refs['tableRef']?.clearSort();
}).catch(err => {
console.log(err);
});
},
goNextDir(item) {
this.filePath.push({
label: item.FileName,
path: item.FileName
});
const dir = this.filePath.map((item) => item.path).join('/');
this.getDirFiles(dir);
},
goBackDir(item) {
const index = this.filePath.findIndex(pth => item === pth);
this.filePath = this.filePath.slice(0, index + 1);
const dir = this.filePath.map((item) => item.path).join('/');
this.getDirFiles(dir);
},
changeVersion(version, noFileRefresh) {
const data = this.modelList.filter((model) => model.version == version)[0];
this.modelType = data.modelType;
this.canOperate = data.isCanOper;
this.canDelete = data.isCanDelete;
this.state.type = data.type;
this.state.typeStr = data.type == 0 ? 'CPU/GPU' : data.type == 1 ? 'NPU' : '';
this.state.id = data.id;
this.state.name = data.name;
this.state.version = data.version;
this.state.engine = data.engine.toString();
this.state.engineName = getListValueWithKey(MODEL_ENGINES, data.engine.toString());
this.state.modelSize = transFileSize(data.size);
this.state.label = data.label || '--';
this.state._label = data.label;
this.state.description = data.description || '--';
this.state._description = data.description;
this.state.createTime = formatDate(new Date(data.createdUnix * 1000), 'yyyy-MM-dd HH:mm:ss');

const trainTaskInfo = data.trainTaskInfo ? JSON.parse(data.trainTaskInfo) : '';
Object.assign(this.state, {
displayJobName: '--',
branchName: '--',
bootFile: '--',
datasetName: '--',
parameters: '--',
workServerNumber: '--',
specStr: '--',
});
if (trainTaskInfo) {
const parameters = trainTaskInfo.Parameters ? JSON.parse(trainTaskInfo.Parameters).parameter : [];
const parametersStr = parameters.map((item) => { return item.label + '=' + item.value }).join('; ');
const taskType = trainTaskInfo.Type;
let taskUrl = location.href.split('modelmanage')[0];
if (taskType == 0) {
taskUrl = taskUrl + 'cloudbrain/train-job/' + trainTaskInfo.JobID;
} else if (taskType == 1) {
taskUrl = taskUrl + 'modelarts/train-job/' + trainTaskInfo.JobID;
} else if (taskType == 2) {
taskUrl = taskUrl + 'grampus/train-job/' + trainTaskInfo.JobID;
}
const versionName = trainTaskInfo.VersionName;
const versionHtml = versionName ? `<span class="append-txt" title="${versionName}">${versionName}</span>` : '';
const codeCommitID = data.codeCommitID;
const codeCommitIDHtml = codeCommitID ? `<span class="append-txt" title="${codeCommitID}">${codeCommitID.slice(0, 10)}</span>` : '';
let specObj;
try {
specObj = trainTaskInfo.FlavorName ? JSON.parse(trainTaskInfo.FlavorName) : '';
} catch (e) {
specObj = trainTaskInfo.FlavorName;
}
const sepcStr = typeof specObj == 'object' ? renderSpecStr(specObj, false) : specObj;
Object.assign(this.state, {
displayJobName: `<a href="${taskUrl}" title="${trainTaskInfo.DisplayJobName}">${trainTaskInfo.DisplayJobName}</a>${versionHtml}`,
branchName: `<span>${trainTaskInfo.BranchName}</span>${codeCommitIDHtml}`,
bootFile: trainTaskInfo.BootFile,
datasetName: trainTaskInfo.DatasetName,
parameters: parametersStr || '--',
workServerNumber: trainTaskInfo.WorkServerNumber || '--',
specStr: sepcStr || '--',
});
}
this.curVersion = version;
if (!noFileRefresh) {
this.filePath = [{ label: version, path: '' }];
this.getDirFiles('')
}
},
goUploadPage() {
window.location.href = `${this.repo}/modelmanage/create_local_model_2?type=1&name=${encodeURIComponent(this.state.name)}&id=${this.state.id}`;
},
backToModelListPage() {
const list = window.location.href.split('/');
list.pop();
list.push('show_model');
window.location.href = list.join('/');
},
labelInput() {
const hasEndSpace = this.editLabel[this.editLabel.length - 1] == ' ';
const list = this.editLabel.trim().split(' ').filter(label => label != '');
this.editLabel = list.slice(0, MAX_LABEL_COUNT).join(' ') + (hasEndSpace && list.length < MAX_LABEL_COUNT ? ' ' : '');
},
submitEidt(type) {
const obj = {
repo: this.repo,
type: this.state.type,
id: this.state.id,
name: this.state.name,
version: this.state.version,
engine: this.state.engine,
label: type == 'label' ? this.editLabel : this.state.label,
description: type == 'descr' ? this.editDescr : this.state.description,
};
modifyModel(obj).then(res => {
res = res.data;
if (res && res.code == '0') {
if (type == 'label') {
this.state.label = this.editLabel;
this.state._label = this.editLabel;
this.isEidtLabel = false;
} else if (type == 'descr') {
this.state.description = this.editDescr;
this.state._description = this.editDescr;
this.isEidtDescr = false;
}
} else {
this.$message({
type: 'error',
message: this.$t('modelManage.infoModificationFailed'),
});
}
}).catch(err => {
console.log(err);
this.$message({
type: 'error',
message: this.$t('modelManage.infoModificationFailed'),
});
});
},
deleteFile(file) {
this.$confirm(this.$t('modelManage.deleteModelFileConfirmTips'), this.$t('tips'), {
confirmButtonText: this.$t('confirm1'),
cancelButtonText: this.$t('cancel'),
type: 'warning',
lockScroll: false,
}).then(() => {
this.loading = true;
deleteModelFile({
repo: this.repo,
id: this.state.id,
fileName: file.FileName,
}).then(res => {
res = res.data;
if (res.code == '0') {
setTimeout(() => {
this.loading = false;
this.updateModelInfo();
const dir = this.filePath.map((item) => item.path).join('/');
this.getDirFiles(dir);
}, 30);
} else {
this.loading = false;
this.$message({
type: 'error',
message: this.$t('modelManage.modelFileDeleteFailed'),
});
}
}).catch(err => {
console.log(err);
this.$message({
type: 'error',
message: this.$t('modelManage.modelFileDeleteFailed'),
});
});
}).catch(() => { });
},
updateModelInfo() {
getModelInfoByName({
repo: this.repo,
name: this.state.name,
}).then(res => {
const list = res.data || [];
this.modelList = list;
const noFileRefresh = true;
this.changeVersion(this.curVersion, noFileRefresh);
}).catch(err => {
console.log(err);
});
},
},
mounted() {
const urlParams = getUrlSearchParams();
if (urlParams.name) {
this.state.name = urlParams.name;
this.loading = true;
getModelInfoByName({
repo: this.repo,
name: urlParams.name,
}).then(res => {
this.loading = false;
const list = res.data || [];
this.modelList = list;
if (list && list.length) {
const data = list[0];
this.changeVersion(data.version);
}
}).catch(err => {
this.loading = false;
console.log(err);
this.backToModelListPage();
});
} else {
this.backToModelListPage();
}
},
beforeDestroy() {
},
};
</script>

<style scoped lang="less">
.header {
display: flex;
align-items: center;

.version {
margin-left: 16px;
width: 90px;
}
}

.content {
.title {
font-weight: 550;
font-size: 14px;
color: rgb(16, 16, 16);
margin-bottom: 10px;
}

.detail-info {
border: 1px solid rgb(232, 232, 232);
border-bottom: none;
padding: 22px;
padding-bottom: 1px;

.area-c {
display: flex;

.area {
flex: 1;

.row {
display: flex;
height: 32px;
margin-bottom: 4px;
align-items: center;

&.edit-row {
height: unset;
}

.tit {
width: 160px;
text-align: right;
color: rgb(136, 136, 136);
}

.val {
flex: 1;
color: rgb(16, 16, 16);
position: relative;
height: 20px;

&.edit-val {
height: unset;
}

.txt-wrap {
position: absolute;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width: 100%;

/deep/.append-txt {
margin-left: 6px;
background-color: gainsboro;
padding: 2px;
border-radius: 2px;
font-size: 12px;
}
}
}

.txt-edit {
padding-right: 20px;
}
}
}
}
}

.expand-line {
display: flex;
align-items: center;
border: 1px solid rgb(232, 232, 232);
border-top: none;
border-bottom: none;
padding: 16px 0;

.line {
flex: 1;
height: 1px;
background-color: rgb(232, 232, 232);
margin: 0 22px;
}

.expand-btn {
color: rgba(22, 132, 252, 1);
cursor: pointer;

.icon {
margin-right: 2px;
font-size: 14px;
color: rgba(22, 132, 252, 0.8),
}
}
}


.files-info {
border: 1px solid rgb(232, 232, 232);
border-top: none;
border-bottom: none;

.top {
padding: 0 22px 8px 22px;
display: flex;
align-items: center;
justify-content: space-between;
}

.files-path-c {
margin-bottom: 4px;
height: 20px;

.file-path {
margin-right: 6px;
float: left;

.path-name {
&.canback {
color: #4183c4;
}
}
}
}

.table-container {
/deep/ .el-table__header {
th {
background: rgb(245, 245, 246);
color: rgb(16, 16, 16);
font-weight: 400;
font-size: 14px;
}
}

/deep/ .el-table__body {
td {
color: rgb(16, 16, 16);
font-weight: 400;
font-size: 14px;
}
}

.tbl-file-name {
height: 32px;
display: flex;
align-items: center;
overflow: hidden;
font-size: 16px;
font-weight: 500;
position: relative;

a {
max-width: 100%;

.fitted {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 100%;
}
}

.disabled-download {
cursor: default;
pointer-events: none;
color: rgba(0, 0, 0, .6) !important;
opacity: .45 !important;
}
}

.btn-del {
color: #0366d6;
cursor: pointer;
}
}
}
}


.el-select-dropdown__item.selected {
color: rgba(0, 0, 0, .95);
}

/deep/ .el-select {
.is-focus {
.el-input__inner {
border-color: #85b7d9;
}
}
}

.el-select {
/deep/ .el-input__inner {
font-weight: 600;
}
}

/deep/ .el-input__inner {
&:focus {
border-color: #85b7d9;
}
}

/deep/ .el-textarea__inner {
&:focus {
border-color: #85b7d9;
}
}
</style>

+ 17
- 0
web_src/vuepages/pages/modelmanage/common/vp-modelmanage-common-detail.js View File

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

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

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

+ 470
- 0
web_src/vuepages/pages/modelmanage/local/modelmanage-local-create-1.vue View File

@@ -0,0 +1,470 @@
<template>
<div>
<div class="header">
<span class="title">{{ type == '1' ? $t('modelManage.modifyModelInfo') : $t('modelManage.importLocalModel')
}}</span>
</div>
<div class="content">
<div class="guide-c" v-if="type != '1'">
<div class="step focused">
<div class="num">1</div>
<div class="txt">{{ $t('modelManage.createModel') }}</div>
</div>
<div class="line"></div>
<div class="step">
<div class="num">2</div>
<div class="txt">{{ $t('modelManage.uploadModelFiles') }}</div>
</div>
</div>
<div class="row-c" v-loading="loading">
<div class="row">
<div class="r-title"><label class="required">{{ $t('modelManage.useCluster') }}</label></div>
<div class="r-content" style="display:flex;">
<div class="cluster-type-btn" v-if="type != 1 || type == 1 && state.type === 0"
:class="state.type === 0 ? 'focused' : ''"
:style="type != 1 ? 'border-top-right-radius:unset;border-bottom-right-radius:unset;' : ''"
@click="state.type = 0; state.engine = '0'">
<svg xmlns="http://www.w3.org/2000/svg"
class="icon styles__StyledSVGIconPathComponent-sc-16fsqc8-0 cSaWDI svg-icon-path-icon fill"
viewBox="0 0 32 32" width="16" height="16">
<defs data-reactroot=""></defs>
<g>
<path
d="M4 3.989c0-0.731 0.593-1.323 1.324-1.323h21.352c0.729 0.005 1.318 0.594 1.324 1.322v24.022c-0.001 0.731-0.593 1.323-1.324 1.323h-21.352c-0.729-0.005-1.318-0.594-1.324-1.322v-24.022zM25.333 14.667v-9.333h-18.667v9.333h18.667zM25.333 17.333h-18.667v9.333h18.667v-9.333zM12 8h8v2.667h-8v-2.667zM12 20h8v2.667h-8v-2.667z">
</path>
</g>
</svg>
<span class="txt">CPU / GPU</span>
</div>
<div class="cluster-type-btn" v-if="type != 1 || type == 1 && state.type === 1"
:class="state.type === 1 ? 'focused' : ''"
:style="type != 1 ? 'border-top-left-radius:unset;border-bottom-left-radius:unset;' : ''"
@click="state.type = 1; state.engine = '2'">
<svg xmlns="http://www.w3.org/2000/svg"
class="icon styles__StyledSVGIconPathComponent-sc-16fsqc8-0 iKfgJk svg-icon-path-icon fill"
viewBox="0 0 32 32" width="16" height="16">
<defs data-reactroot=""></defs>
<g>
<path
d="M4 3.989c0-0.731 0.593-1.323 1.324-1.323h21.352c0.729 0.005 1.318 0.594 1.324 1.322v24.022c-0.001 0.731-0.593 1.323-1.324 1.323h-21.352c-0.729-0.005-1.318-0.594-1.324-1.322v-24.022zM25.333 14.667v-9.333h-18.667v9.333h18.667zM25.333 17.333h-18.667v9.333h18.667v-9.333zM12 8h8v2.667h-8v-2.667zM12 20h8v2.667h-8v-2.667z">
</path>
</g>
</svg>
<span class="txt">Ascend NPU</span>
</div>
</div>
</div>
<div class="row" :class="nameErr ? 'error' : ''">
<div class="r-title"><label class="required">{{ $t('modelManage.modelName') }}</label></div>
<div class="r-content">
<el-input size="medium" :maxLength="25" v-model="state.name" @blur="checkName"
:placeholder="$t('modelManage.pleaseInputModelName')">
</el-input>
</div>
</div>
<div class="row" v-show="isShowVersion">
<div class="r-title"><label class="required">{{ $t('modelManage.version') }}</label></div>
<div class="r-content">
<el-input class="input-disabled" style="width:288px;" size="medium" v-model="state.version" readonly>
</el-input>
</div>
</div>
<div class="row">
<div class="r-title"><label class="required">{{ $t('modelManage.modelEngine') }}</label></div>
<div class="r-content">
<el-select style="width:288px;" size="medium" v-model="state.engine" placeholder="">
<el-option v-for="item in engineList" :key="item.k" :label="item.v" :value="item.k">
</el-option>
</el-select>
</div>
</div>
<div class="row">
<div class="r-title"><label>{{ $t('modelManage.modelLabel') }}</label></div>
<div class="r-content">
<el-input size="medium" :maxLength="255" v-model="state.label"
:placeholder="$t('modelManage.modelLabelInputTips')" @input="labelInput"></el-input>
</div>
</div>
<div class="row" style="align-items:flex-start;">
<div class="r-title"><label>{{ $t('modelManage.modelDescr') }}</label></div>
<div class="r-content">
<el-input type="textarea" :maxLength="255" size="medium" v-model="state.description" :rows="3"
:placeholder="$t('modelManage.modelDescrInputTips')">
</el-input>
</div>
</div>
<div class="row" style="margin-top:20px">
<div class="r-title"><label></label></div>
<div class="r-content">
<el-button size="medium" class="green" @click="submit">{{ type == '1' ? $t('modelManage.confirm') :
$t('modelManage.createModel')
}}
</el-button>
<el-button size="medium" @click="cancel">{{ $t('modelManage.cancel') }}</el-button>
</div>
</div>
</div>
</div>
</div>
</template>

<script>

import { saveLocalModel, getModelInfoByName, modifyModel } from '~/apis/modules/modelmanage';
import { getUrlSearchParams } from '~/utils';
import { MODEL_ENGINES } from '~/const'

const REPO_NAME = location.pathname.split('/')[2];
const MAX_LABEL_COUNT = 5;

export default {
data() {
return {
type: '0', // 1-修改,其它-新增
loading: false,
state: {
type: 0,
name: REPO_NAME + '_model_' + Math.random().toString(36).substr(2, 4),
version: '0.0.1',
engine: '0',
label: '',
description: '',
},
nameErr: false,
isShowVersion: false,
engineList: MODEL_ENGINES,
};
},
components: {},
methods: {
checkName() {
this.nameErr = !this.state.name;
return !this.nameErr;
},
labelInput() {
const hasEndSpace = this.state.label[this.state.label.length - 1] == ' ';
const list = this.state.label.trim().split(' ').filter(label => label != '');
this.state.label = list.slice(0, MAX_LABEL_COUNT).join(' ') + (hasEndSpace && list.length < MAX_LABEL_COUNT ? ' ' : '');
},
submit() {
if (!this.checkName()) {
// this.$message({
// type: 'info',
// message: this.$t('modelManage.pleaseInputModelName'),
// });
return;
}
const submintApi = this.type == '1' ? modifyModel : saveLocalModel;
submintApi({
repo: location.pathname.split('/').slice(0, 3).join('/'),
...this.state,
}).then(res => {
res = res.data;
if (res && res.code == '0') {
if (this.type == '1') {
this.goDetail();
return;
}
const list = window.location.href.split('/');
list.pop();
list.push('create_local_model_2');
window.location.href = list.join('/') + '?type=0&name=' + encodeURIComponent(this.state.name) + '&id=' + res.id;
} else if (res && res.code == '-1') {
this.$message({
type: 'error',
message: res.msg,
});
} else {
this.$message({
type: 'error',
message: this.type == '1' ? this.$t('modelManage.modelModifyFailed') : this.$t('modelManage.modelCreateFailed'),
});
}
}).catch(err => {
console.log(err);
});
},
cancel() {
const list = window.location.href.split('/');
list.pop();
list.push('show_model');
window.location.href = list.join('/');
},
goDetail() {
const list = window.location.href.split('/');
list.pop();
list.push('show_model_info');
window.location.href = list.join('/') + '?name=' + encodeURIComponent(this.state.name);
}
},
mounted() {
const urlParams = getUrlSearchParams();
if (urlParams.type == '1' && urlParams.name && urlParams.id) { // update
this.type = urlParams.type;
this.state.name = urlParams.name;
this.state.id = urlParams.id;
this.loading = true;
getModelInfoByName({
repo: location.pathname.split('/').slice(0, 3).join('/'),
name: urlParams.name,
id: urlParams.id
}).then(res => {
this.loading = false;
const list = res.data;
if (list && list.length) {
const data = list[0];
this.state.type = data.type;
this.state.id = data.id;
this.state.name = data.name;
this.state.version = data.version;
this.state.engine = data.engine.toString();
this.state.label = data.label;
this.state.description = data.description;
}
}).catch(err => {
this.loading = false;
console.log(err);
this.cancel();
});
}
},
beforeDestroy() {
},
};
</script>

<style scoped lang="less">
.header {
height: 45px;
border-color: rgb(212, 212, 213);
border-width: 1px;
border-style: solid;
border-radius: 5px 5px 0px 0px;
font-size: 14px;
background: rgb(240, 240, 240);
display: flex;
align-items: center;

.title {
font-weight: 600;
font-size: 16px;
color: rgb(16, 16, 16);
margin-left: 10px;
}
}

.content {
margin-top: -1px;
border-color: rgb(212, 212, 213);
border-width: 1px;
border-style: solid;
padding: 30px 0;
border-top: none;

.guide-c {
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 20px;

.step {
display: flex;
align-items: center;
color: rgb(136, 136, 136);

.num {
border: 1px solid rgb(136, 136, 136);
width: 34px;
height: 34px;
font-size: 24px;
text-align: center;
line-height: 34px;
border-radius: 17px;
margin-right: 8px;
}

.txt {
font-weight: 600;
}

&.focused {
color: rgb(22, 132, 252);

.num {
border-color: rgb(22, 132, 252);
}
}
}

.line {
height: 2px;
width: 50px;
background-color: rgb(187, 187, 187);
margin: 0 10px;
}
}

.row-c {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
margin: 0 auto;
width: 80%;

.row {
width: 100%;
display: flex;
align-items: center;
margin: 8px 0;
margin-left: -190px;

.r-title {
text-align: right;
font-size: .92857143em;
font-weight: 700;
color: rgba(0, 0, 0, .87);
width: 200px;
margin-right: 28px;
position: relative;

.required {
&::after {
position: absolute;
margin: -0.2em 0 0 0.2em;
content: '*';
color: #db2828;
}
}
}

&.error {
.r-title {
color: #9f3a38;
}

.r-content {
/deep/.el-input__inner {
color: #9f3a38;
background: #fff6f6;
border-color: #e0b4b4;

&::placeholder {
color: #e0b4b4;
}
}
}
}

.r-content {
flex: 1;

.cluster-type-btn {
display: flex;
align-items: center;
justify-content: center;
border: 1px solid #DCDFE6;
height: 36px;
padding: 10px;
cursor: pointer;
border-radius: 4px;

.icon {
margin-right: 5px;
}

&.focused {
border-color: rgb(50, 145, 248);
color: rgb(50, 145, 248);
cursor: default;

.icon {
:not([stroke]) {
fill: rgb(50, 145, 248);
}
}
}
}
}
}
}
}

.input-disabled {
/deep/ .el-input__inner {
background-color: #f5f5f6 !important;
color: #888888 !important;
}
}

.el-select-dropdown__item.selected {
color: rgba(0, 0, 0, .95);
}

/deep/ .el-button {
background-color: #e0e1e2;
color: rgba(0, 0, 0, .6);
border-color: transparent;
transition: opacity .1s ease, background-color .1s ease, color .1s ease, box-shadow .1s ease, background .1s ease, -webkit-box-shadow .1s ease;
will-change: auto;
-webkit-tap-highlight-color: transparent;

&:hover {
border-color: transparent;
background-color: #cacbcd;
color: rgba(0, 0, 0, .8);
}

&:focus {
background-color: #cacbcd;
color: rgba(0, 0, 0, .8);
border-color: transparent;
}

&:active {
background-color: #babbbc;
color: rgba(0, 0, 0, .9);
border-color: transparent;
}

&.green {
background-color: #5bb973;
color: #fff;

&:hover {
background-color: #16ab39;
border-color: transparent;
}

&:focus {
background-color: #0ea432;
border-color: transparent;
}

&:active {
background-color: #198f35;
border-color: transparent;
}
}
}

/deep/ .el-select {
.is-focus {
.el-input__inner {
border-color: #85b7d9;
}
}
}

/deep/ .el-input__inner {
&:focus {
border-color: #85b7d9;
}
}

/deep/ .el-textarea__inner {
&:focus {
border-color: #85b7d9;
}
}
</style>

+ 851
- 0
web_src/vuepages/pages/modelmanage/local/modelmanage-local-create-2.vue View File

@@ -0,0 +1,851 @@
<template>
<div>
<div class="header">
<span class="title">{{ type == '1' ? $t('modelManage.addModelFiles') : $t('modelManage.uploadModelFiles')
}}</span>
</div>
<div class="content ui form">
<div class="guide-c" v-if="type != '1'">
<div class="step">
<div class="num">1</div>
<div class="txt">{{ $t('modelManage.createModel') }}</div>
</div>
<div class="line"></div>
<div class="step focused">
<div class="num">2</div>
<div class="txt">{{ $t('modelManage.uploadModelFiles') }}</div>
</div>
</div>
<div class="row-c">
<div class="row">
<div class="r-title"><label class="required">{{ $t('modelManage.modelName') }}</label></div>
<div class="r-content">
<el-input size="medium" class="input-disabled" v-model="state.name"
:placeholder="$t('modelManage.pleaseInputModelName')" readonly>
</el-input>
</div>
</div>
<div class="row" style="align-items:flex-start;">
<div class="r-title"><label class="required">{{ $t('modelManage.fileUpload') }}</label></div>
<div class="r-content">
<div style="position:relative">
<form class="dropzone" ref="dropzoneRef">
<div class="dropzon-err-tips ui red message" v-show="showUploadErr" style="display:none;margin:2.5rem">
{{ uploadErrTxt }}</div>
</form>
<div class="not-allowed-placeholder" v-show="uploading"></div>
</div>
</div>
</div>
<div class="row" style="margin-top:10px">
<div class="r-title"><label></label></div>
<div class="r-content">
<el-button size="medium" class="green" @click="submit" :disabled="uploading">{{ $t('modelManage.upload') }}
</el-button>
<el-button size="medium" @click="cancel">{{ $t('modelManage.cancel') }}</el-button>
</div>
</div>
<div class="row" style="align-items:flex-start;">
<div class="r-title"><label>{{ $t('modelManage.uploadStatus') }}:</label></div>
<div class="r-content">
<div v-for="(item, index) in uploadFiles" :key="item.upload.uuid" class="datast-upload-progress">
<span class="dataset-name nowrap" :title="item.name">{{ item.name }}</span>
<div class="dataset-progress">
<el-progress :text-inside="true" :stroke-width="14" :percentage="uploadStatusList[index].progress">
</el-progress>
</div>
<div class="dataset-status nowrap">
<div class="status-flex">
<i v-if="uploadStatusList[index].infoCode === 1 || uploadStatusList[index].infoCode === 2"
class="ri-close-circle-line failed"></i>
<i v-if="uploadStatusList[index].infoCode === 0" class="ri-checkbox-circle-line success"></i>
<span>{{ uploadStatusList[index].status }}</span>
<el-tooltip v-if="uploadStatusList[index].infoCode === 1" class="item" effect="dark" placement="top">
<div slot="content"> {{ uploadStatusList[index].failedInfo }} </div>
<i style="font-size: 16px; margin-left: 0.5rem; cursor: pointer" class="ri-question-fill"></i>
</el-tooltip>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>

<script>

import 'dropzone/dist/dropzone.css';
import Dropzone from 'dropzone';
import SparkMD5 from "spark-md5";
import { getModelInfoByName, getChunks, getNewMultipart, getMultipartUrl, setCompleteMultipart } from '~/apis/modules/modelmanage';
import { getUrlSearchParams } from '~/utils';

Dropzone.autoDiscover = false;

const uploadChunkSize = 1024 * 1024 * 64;
const md5ChunkSize = 1024 * 1024 * 64;
const maxFileSize = 10;
const maxModelFilesSize = window.MAX_MODEL_SIZE || 200 * 1024 * 1024 * 1024; // 200 GB

export default {
data() {
return {
dropzoneHandler: null,
type: '0', // 1-修改,其它-新增
state: {
type: '',
id: '',
name: '',
version: '',
engine: '',
label: '',
description: '',
size: 0,
},
originData: null,
showUploadErr: false,
uploadErrTxt: '',

uploadFiles: [],
uploadLength: 0,
uploadSuccessLength: 0,
uploadStatusList: [],

uploading: false,
};
},
components: {},
methods: {
initModelData() {
const urlParams = getUrlSearchParams();
if (urlParams.name && urlParams.id) {
this.type = urlParams.type || '0';
this.state.name = urlParams.name;
this.state.id = urlParams.id;
this.loading = true;
getModelInfoByName({
repo: location.pathname.split('/').slice(0, 3).join('/'),
name: urlParams.name,
id: urlParams.id
}).then(res => {
this.loading = false;
const list = res.data;
if (list && list.length) {
const data = list[0];
this.state.type = data.type;
this.state.id = data.id;
this.state.name = data.name;
this.state.version = data.version;
this.state.engine = data.engine.toString();
this.state.label = data.label;
this.state.description = data.description;
this.state.size = data.size || 0;
this.originData = data;
} else {
this.cancel();
}
}).catch(err => {
this.loading = false;
console.log(err);
this.cancel();
});
} else {
this.cancel();
}
},
initDropZone() {
this.dropzoneHandler = new Dropzone(this.$refs.dropzoneRef, {
url: '/',
maxFiles: 10,
parallelUploads: 20,
uploadMultiple: true,
maxFilesize: maxModelFilesSize,
timeout: 0,
addRemoveLinks: true,
autoProcessQueue: false,
dictDefaultMessage: this.$t('modelManage.modelFileUploadDefaultTips'),
dictFileTooBig: this.$t('modelManage.fileIstoBig'),
dictRemoveFile: this.$t('modelManage.removeFile'),
dictMaxFilesExceeded: this.getDefaultErrTxt(),
});
this.dropzoneHandler.on("addedfile", file => {
this.checkFiles(file);
});
this.dropzoneHandler.on("removedfile", file => {
this.checkFiles();
});
},
getDefaultErrTxt() {
return this.$t('modelManage.modelFileUploadErrTips', { size: (maxModelFilesSize / (1024 * 1024 * 1024)).toFixed(2) });
},
showUploadErrInfo(state, info) {
if (state) {
this.uploadErrTxt = info;
this.showUploadErr = true;
} else {
this.uploadErrTxt = '';
this.showUploadErr = false;
}
},
checkFiles(file, countStay) {
const fileList = this.dropzoneHandler.getAcceptedFiles();
const filesSize = fileList.reduce((acc, item, index) => acc + item.size, 0) + (file && !countStay ? file.size : 0);
const filesCount = fileList.length + (file && !countStay ? 1 : 0);
const allfilesSize = filesSize + this.state.size;
if (file && filesCount > maxFileSize) {
this.dropzoneHandler.removeFile(file);
this.showUploadErrInfo(true, this.getDefaultErrTxt());
return false;
}
if (filesCount > maxFileSize || allfilesSize > maxModelFilesSize) {
this.showUploadErrInfo(true, this.getDefaultErrTxt());
return false;
}
if (file && file.name.length > 128) {
this.showUploadErrInfo(true, this.$t('modelManage.modelFileNameTips'));
this.uploadError(file, this.$t('modelManage.modelFileNameTips'));
return false;
}
this.showUploadErrInfo(false);
return true;
},
resetFileStatus() {
this.uploadFiles = [];
this.uploadLength = 0;
this.uploadSuccessLength = 0;
this.uploadStatusList = [];
},
updateFileStatus(file, status, progress, infoCode, failedInfo = "") {
this.uploadStatusList.forEach((item, index) => {
if (item.uploadUuid === file.upload.uuid) {
this.uploadStatusList[index].status = status;
this.uploadStatusList[index].progress = progress;
this.uploadStatusList[index].infoCode = infoCode;
this.uploadStatusList[index].failedInfo = failedInfo;
}
});
},
calcFileMd5(file) {
const blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;
const chunkSize = md5ChunkSize;
const chunks = Math.ceil(file.size / chunkSize);
const spark = new SparkMD5.ArrayBuffer();
const fileReader = new FileReader();
file.totalChunkCounts = chunks;
if (file.size == 0) {
file.totalChunkCounts = 1;
}
let currentChunk = 0;
this.uploadStatusList.push({
uploadUuid: file.upload.uuid,
name: file.name,
status: this.$t('modelManage.calcFileMd5'),
progress: 0,
infoCode: 3,
});
return new Promise((resolve, reject) => {
fileReader.onload = function (e) {
spark.append(e.target.result);
currentChunk++;
if (currentChunk < chunks) {
loadNext();
} else {
const md5 = spark.end();
spark.destroy();
file.uniqueIdentifier = md5;
resolve(md5);
}
};
fileReader.onerror = function (e) {
console.warn(file.name + ': calcFileMd5 went wrong.');
reject(e);
};

function loadNext() {
const start = currentChunk * chunkSize;
const end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;
fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
}
loadNext();
});
},
getChunksInfo(file) {
return getChunks({
md5: file.uniqueIdentifier,
type: this.state.type,
modeluuid: this.state.id,
file_name: file.name,
scene: 'model',
}).then(res => {
const data = res.data;
file.uploadID = data.uploadID;
file.uuid = data.uuid;
file.uploaded = data.uploaded;
file.chunks = data.chunks;
file.attachID = data.attachID;
file._modelUuid = data.modeluuid;
file._modelName = data.modelName;
file.realName = data.fileName;
return file;
}).catch(err => {
console.info('getChunksInfo', err);
return err;
});
},
newUpload(file) {
return getNewMultipart({
totalChunkCounts: file.totalChunkCounts,
md5: file.uniqueIdentifier,
size: file.size,
fileType: file.type,
type: this.state.type,
file_name: file.name,
scene: 'model',
modeluuid: file.modelUuid,
}).then(res => {
const data = res.data;
file.uploadID = data.uploadID;
file.uuid = data.uuid;
if (file.uploadID && file.uuid) {
file.chunks = '';
this.breakpointUpload(file);
} else {
this.uploadError(file, info);
this.updateFileStatus(file, this.$t('modelManage.uploadFailed'), 0, 2);
}
return file;
}).catch(err => {
console.log('getNewMultipart', err);
this.uploadError(file, info);
this.updateFileStatus(file, this.$t('modelManage.uploadFailed'), 0, 2);
return err;
});
},
breakpointUpload(file) {
const blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;
const fileReader = new FileReader();
const time = new Date().getTime();
const chunkSize = uploadChunkSize;
const chunks = Math.ceil(file.size / chunkSize);
const _this = this;
let currentChunk = 0;
const successChunks = [];
const successParts = file.chunks.split(",");
for (let i = 0; i < successParts.length; i++) {
successChunks[i] = successParts[i].split("-")[0];
}
const urls = [];
const etags = [];
const checkSuccessChunks = () => {
const index = successChunks.indexOf((currentChunk + 1).toString());
if (index == -1) {
return false;
}
return true;
}

const getUploadChunkUrl = async (currentChunk, partSize) => {
const res = await getMultipartUrl({
uuid: file.uuid,
uploadID: file.uploadID,
size: partSize,
chunkNumber: currentChunk + 1,
type: _this.state.type,
file_name: file.name,
scene: 'model',
});
urls[currentChunk] = res.data.url;
};

const uploadMinioNewMethod = async (url, e) => {
const xhr = new XMLHttpRequest();
xhr.open("PUT", url, false);
if (_this.state.type == 0) {
xhr.setRequestHeader("Content-Type", "text/plain");
xhr.send(e.target.result);
const etagValue = xhr.getResponseHeader("etag");
etags[currentChunk] = etagValue;
} else if (_this.state.type == 1) {
xhr.setRequestHeader("Content-Type", "");
xhr.send(e.target.result);
const etagValue = xhr.getResponseHeader("ETag");
etags[currentChunk] = etagValue;
}
}

const uploadChunk = async (e) => {
try {
if (!checkSuccessChunks()) {
const start = currentChunk * chunkSize;
const partSize = start + chunkSize >= file.size ? file.size - start : chunkSize;
// 获取分片上传url
await getUploadChunkUrl(currentChunk, partSize);
if (urls[currentChunk] != '') {
await uploadMinioNewMethod(urls[currentChunk], e);
if (etags[currentChunk] != '') {
} else {
console.log("上传到minio uploadChunk etags[currentChunk] == ''"); // TODO
}
} else {
console.log("uploadChunk urls[currentChunk] != ''"); // TODO
}
}
} catch (error) {
console.log(error);
}
}

const completeUpload = async () => {
return await setCompleteMultipart({
uuid: file.uuid,
uploadID: file.uploadID,
file_name: file.name,
size: file.size,
type: _this.state.type,
scene: 'model',
modeluuid: file.modelUuid,
});
}

function loadNext() {
const start = currentChunk * chunkSize;
const end = start + chunkSize >= file.size ? file.size : start + chunkSize;
fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
}

fileReader.onload = async (e) => {
try {
await uploadChunk(e);
fileReader.abort();
currentChunk++;
if (currentChunk < chunks) {
console.log(`第${currentChunk}个分片上传完成, 开始第${currentChunk + 1}/${chunks}个分片上传`);
this.updateFileStatus(file, this.$t('modelManage.uploading'), Number(((currentChunk / chunks) * 100).toFixed(2)), 3);
loadNext();
} else {
try {
await completeUpload();
console.log(`文件上传完成:${file.name} \n分片:${chunks} 大小:${file.size} 用时:${(new Date().getTime() - time) / 1000} s`);
this.uploadLength++;
this.uploadSuccessLength++;
this.updateFileStatus(file, this.$t('modelManage.uploadSuccess'), 100, 0);
this.uploadSuccess(file);
} catch (err) {
const info = this.$t('modelManage.uploadFailed');
console.log(info, file)
this.uploadLength++;
this.uploadError(file, info);
this.updateFileStatus(file, info, Number(((currentChunk / chunks) * 100).toFixed(2)) - 1, 2);
}
}
} catch (err) {
console.log(err);
const info = this.$t('modelManage.uploadFailed');
console.log(info, file)
this.uploadLength++;
this.uploadError(file, info);
this.updateFileStatus(file, info, Number(((currentChunk / chunks) * 100).toFixed(2)) - 1, 2);
}
};
console.log("上传分片...");
loadNext();
},
uploadError(file, info) {
file.previewTemplate.querySelector('.dz-success-mark').style.opacity = 0;
file.previewTemplate.querySelector('.dz-error-mark').style.opacity = 1;
file.previewTemplate.querySelector('.dz-error-message span').innerHTML = info;
file.previewTemplate.querySelector(".dz-error-message").style.display = 'block';
file.previewTemplate.querySelector(".dz-details").onmouseover = () => {
file.previewTemplate.querySelector('.dz-error-message').style.opacity = 1;
};
file.previewTemplate.querySelector(".dz-details").onmouseout = () => {
file.previewTemplate.querySelector('.dz-error-message').style.opacity = 0;
};
this.uploadFinishCheck(file);
},
uploadSuccess(file) {
file.previewTemplate.querySelector('.dz-error-mark').style.opacity = 0;
file.previewTemplate.querySelector('.dz-error-message span').innerHTML = '';
file.previewTemplate.querySelector('.dz-success-mark').style.opacity = 1;
file.previewTemplate.querySelector(".dz-error-message").style.display = 'none';
file.previewTemplate.querySelector(".dz-details").onmouseover = null;
file.previewTemplate.querySelector(".dz-details").onmouseout = null;
this.uploadFinishCheck(file);
},
uploadFinishCheck(file) {
console.log('uploadFinishCheck', file, this.uploadLength, '/', this.uploadFiles.length);
if (this.uploadLength === this.uploadFiles.length && this.uploadFiles.length != 0) {
console.log('All file has finish, success ' + this.uploadSuccessLength);
this.uploading = false;
if (this.uploadSuccessLength == this.uploadLength) {
window.setTimeout(() => {
this.goDetail();
}, 1000);
} else {
if (this.uploadSuccessLength > 0) {
this.initModelData();
}
}
}
},
submit() {
const fileList = this.dropzoneHandler.getAcceptedFiles();
if (!fileList.length) return;
for (let i = 0, iLen = fileList.length; i < iLen; i++) {
if (!this.checkFiles(fileList[i], true)) return;
}
this.resetFileStatus();
this.uploadFiles = fileList;
this.uploading = true;
for (let i = 0, iLen = fileList.length; i < iLen; i++) {
const file = fileList[i];
file.modelUuid = this.state.id;
file.modelName = this.state.name;
this.calcFileMd5(file).then(res => { // 计算MD5
this.getChunksInfo(file).then(res => { // 获取Chunk信息
if (file.uploadID == '' || file.uuid == '') { // 未上传过
this.newUpload(file);
} else if (file.uploaded == '1') { // 已上传成功
if (file.attachID == '0') { // 删除数据集记录,未删除文件
// await addAttachment(file);
console.log(`file.attachID == '0'`);
}
this.uploadLength++;
// 同一模型上传同一个文件
if (file._modelUuid) {
const info = `${this.$t('modelManage.fileHasAlreadyInTheModel')} ${file._modelName}`;
this.uploadError(file, info);
this.updateFileStatus(file, this.$t('modelManage.uploadFailed'), 0, 1, info);
} else { // 秒传
this.uploadSuccessLength++;
this.updateFileStatus(file, this.$t('modelManage.uploadSuccess'), 100, 0);
this.uploadSuccess(file);
}
console.log(file.name, '文件处理完成');
} else { // 断点续传
this.breakpointUpload(file);
}
}).catch(err => {
console.info('getChunksInfo', err);
this.uploadLength++;
this.uploadError(file, this.$t('modelManage.uploadFailed'));
this.updateFileStatus(file, this.$t('modelManage.uploadFailed'), 0, 2);
});
}).catch(err => {
console.info('calcFileMd5', err);
this.uploadLength++;
this.uploadError(file, this.$t('modelManage.uploadFailed'));
this.updateFileStatus(file, this.$t('modelManage.uploadFailed'), 0, 2);
});
}
},
cancel() {
if (this.type == '1') {
this.goDetail();
return;
}
const list = window.location.href.split('/');
list.pop();
list.push('show_model');
window.location.href = list.join('/');
},
goDetail() {
const list = window.location.href.split('/');
list.pop();
list.push('show_model_info');
window.location.href = list.join('/') + '?name=' + this.state.name;
}
},
mounted() {
this.initModelData();
this.initDropZone();
},
beforeDestroy() {
},
};
</script>

<style scoped lang="less">
.header {
height: 45px;
border-color: rgb(212, 212, 213);
border-width: 1px;
border-style: solid;
border-radius: 5px 5px 0px 0px;
font-size: 14px;
background: rgb(240, 240, 240);
display: flex;
align-items: center;

.title {
font-weight: 600;
font-size: 16px;
color: rgb(16, 16, 16);
margin-left: 10px;
}
}

.content {
margin-top: -1px;
border-color: rgb(212, 212, 213);
border-width: 1px;
border-style: solid;
padding: 30px 0;
border-top: none;

.guide-c {
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 20px;

.step {
display: flex;
align-items: center;
color: rgb(136, 136, 136);

.num {
border: 1px solid rgb(136, 136, 136);
width: 34px;
height: 34px;
font-size: 24px;
text-align: center;
line-height: 34px;
border-radius: 17px;
margin-right: 8px;
}

.txt {
font-weight: 600;
}

&.focused {
color: rgb(22, 132, 252);

.num {
border-color: rgb(22, 132, 252);
}
}
}

.line {
height: 2px;
width: 50px;
background-color: rgb(187, 187, 187);
margin: 0 10px;
}
}

.row-c {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
margin: 0 auto;

.row {
width: 100%;
display: flex;
align-items: center;
margin: 8px 0;
margin-left: -190px;

.r-title {
text-align: right;
font-size: .92857143em;
font-weight: 700;
color: rgba(0, 0, 0, .87);
width: 200px;
margin-right: 28px;
position: relative;

.required {
&::after {
position: absolute;
margin: -0.2em 0 0 0.2em;
content: '*';
color: #db2828;
}
}
}

.r-content {
flex: 1;

.cluster-type-btn {
display: flex;
align-items: center;
justify-content: center;
border: 1px solid #DCDFE6;
height: 36px;
padding: 10px;
cursor: pointer;
border-radius: 4px;

.icon {
margin-right: 5px;
}

&.focused {
border-color: rgb(50, 145, 248);
color: rgb(50, 145, 248);
cursor: default;

.icon {
:not([stroke]) {
fill: rgb(50, 145, 248);
}
}
}
}
}
}
}
}

.not-allowed-placeholder {
position: absolute;
width: 100%;
height: 100%;
z-index: 20;
cursor: no-drop;
top: 0;
}

.dropzone {
min-height: 186px !important;

/deep/ .dz-default.dz-message {
margin: 76px 0 !important;
}

/deep/ .dz-remove {
margin-top: 10px !important;
}
}

.input-disabled {
/deep/ .el-input__inner {
background-color: #f5f5f6 !important;
color: #888888 !important;
}
}

/deep/ .dz-progress {
display: none;
}

.success {
color: #21ba45;
font-size: 16px;
margin-right: 0.5rem;
}

.failed {
color: red;
font-size: 16px;
margin-right: 0.5rem;
}

.datast-upload-progress {
display: flex;
align-items: center;
}

.datast-upload-progress .dataset-name {
text-align: right;
width: 200px;
margin-right: 1rem;
}

.datast-upload-progress .dataset-progress {
flex: 1;
}

.datast-upload-progress .dataset-status {
width: 140px;
margin-left: 1rem;
}

.datast-upload-progress .dataset-status .status-flex {
display: flex;
align-items: center;
}

/deep/ .el-progress-bar__inner {
background-color: #21ba45;
}

.el-select-dropdown__item.selected {
color: #85b7d9;
}

/deep/ .el-button {
background-color: #e0e1e2;
color: rgba(0, 0, 0, .6);
border-color: transparent;
transition: opacity .1s ease, background-color .1s ease, color .1s ease, box-shadow .1s ease, background .1s ease, -webkit-box-shadow .1s ease;
will-change: auto;
-webkit-tap-highlight-color: transparent;

&:hover {
border-color: transparent;
background-color: #cacbcd;
color: rgba(0, 0, 0, .8);
}

&:focus {
background-color: #cacbcd;
color: rgba(0, 0, 0, .8);
border-color: transparent;
}

&:active {
background-color: #babbbc;
color: rgba(0, 0, 0, .9);
border-color: transparent;
}

&.green {
background-color: #5bb973;
color: #fff;

&:hover {
background-color: #16ab39;
border-color: transparent;
}

&:focus {
background-color: #0ea432;
border-color: transparent;
}

&:active {
background-color: #198f35;
border-color: transparent;
}
}
}

/deep/ .el-select {
.is-focus {
.el-input__inner {
border-color: #85b7d9;
}
}
}

/deep/ .el-input__inner {
&:focus {
border-color: #85b7d9;
}
}

/deep/ .el-textarea__inner {
&:focus {
border-color: #85b7d9;
}
}
</style>

+ 17
- 0
web_src/vuepages/pages/modelmanage/local/vp-modelmanage-local-create-1.js View File

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

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

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

+ 17
- 0
web_src/vuepages/pages/modelmanage/local/vp-modelmanage-local-create-2.js View File

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

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

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

+ 9
- 7
web_src/vuepages/pages/resources/components/SceneDialog.vue View File

@@ -69,7 +69,9 @@
</div>
<div class="content">
<el-select v-model="dataInfo.SpecIds" multiple collapse-tags class="specSel">
<el-option v-for="item in specsList" :key="item.k" :label="item.v" :value="item.k" />
<el-option v-for="item in specsList" :label="item.v" :key="item.k" :value="item.k">
<span v-html="item.v"></span>
</el-option>
</el-select>
</div>
</div>
@@ -87,7 +89,7 @@
</template>
<script>
import BaseDialog from '~/components/BaseDialog.vue';
import { getResQueueCode, getResSpecificationList, addResScene, updateResScene } from '~/apis/modules/resources';
import { getResQueueCode, getResSpecificationListAll, addResScene, updateResScene } from '~/apis/modules/resources';
import { JOB_TYPE, CLUSTERS, ACC_CARD_TYPE, SPECIFICATION_STATUS } from '~/const';
import { getListValueWithKey } from '~/utils';

@@ -167,21 +169,21 @@ export default {
const params = {
cluster: this.dataInfo.Cluster,
queue: this.dataInfo.QueueId === '-1' ? '' : this.dataInfo.QueueId,
status: 2,
page: 1,
// status: 2,
// page: 1,
};
return getResSpecificationList(params).then(res => {
return getResSpecificationListAll(params).then(res => {
res = res.data;
if (res.Code === 0) {
const list = res.Data.List;
const data = list.map((item) => {
const Queue = item.Queue;
const Spec = item.Spec;
// const NGPU = `${Queue.ComputeResource}:${Spec.AccCardsNum === 0 ? '0' : Spec.AccCardsNum + '*' + getListValueWithKey(this.accCardTypeList, Queue.AccCardType)}`;
const NGPU = `${Queue.ComputeResource}:${Spec.AccCardsNum + '*' + getListValueWithKey(this.accCardTypeList, Queue.AccCardType)}`;
const statusStr = Spec.Status != '2' ? `<span style="color:rgb(245, 34, 45)">(${getListValueWithKey(this.statusList, Spec.Status.toString())})</span>` : '';
return {
k: Spec.ID,
v: `${NGPU}, CPU:${Spec.CpuCores}, ${this.$t('resourcesManagement.gpuMem')}:${Spec.GPUMemGiB}GB, ${this.$t('resourcesManagement.mem')}:${Spec.MemGiB}GB, ${this.$t('resourcesManagement.shareMem')}:${Spec.ShareMemGiB}GB, ${this.$t('resourcesManagement.unitPrice')}:${Spec.UnitPrice}${this.$t('resourcesManagement.point_hr')}`,
v: `${NGPU}, CPU:${Spec.CpuCores}, ${this.$t('resourcesManagement.gpuMem')}:${Spec.GPUMemGiB}GB, ${this.$t('resourcesManagement.mem')}:${Spec.MemGiB}GB, ${this.$t('resourcesManagement.shareMem')}:${Spec.ShareMemGiB}GB, ${this.$t('resourcesManagement.unitPrice')}:${Spec.UnitPrice}${this.$t('resourcesManagement.point_hr')}${statusStr}`,
}
});
this.specsList.splice(0, Infinity, ...data);


+ 5
- 4
web_src/vuepages/pages/resources/scene/index.vue View File

@@ -64,7 +64,7 @@
header-align="center" min-width="180">
<template slot-scope="scope">
<div v-for="item in scope.row.SpecsList" :key="item.k">
<span>{{ item.v }}</span>
<span v-html="item.v"></span>
</div>
</template>
</el-table-column>
@@ -100,7 +100,7 @@
<script>
import SceneDialog from '../components/SceneDialog.vue';
import { getQueueList, getResQueueCode, getResSceneList, updateResScene, getAiCenterList } from '~/apis/modules/resources';
import { JOB_TYPE, CLUSTERS, ACC_CARD_TYPE } from '~/const';
import { JOB_TYPE, CLUSTERS, ACC_CARD_TYPE, SPECIFICATION_STATUS } from '~/const';
import { getListValueWithKey } from '~/utils';
import { formatDate } from 'element-ui/lib/utils/date-util';

@@ -117,6 +117,7 @@ export default {
selAiCenter: '',
aiCenterList: [{ k: '', v: this.$t('resourcesManagement.allAiCenter') }],
accCardTypeList: [...ACC_CARD_TYPE],
statusList: [{ k: '', v: this.$t('resourcesManagement.allStatus') }, ...SPECIFICATION_STATUS],
loading: false,
tableData: [],
pageInfo: {
@@ -191,11 +192,11 @@ export default {
let cluster = '';
for (let i = 0, iLen = Specs.length; i < iLen; i++) {
const Spec = Specs[i];
// const NGPU = `${Spec.ComputeResource}:${Spec.AccCardsNum === 0 ? '0' : Spec.AccCardsNum + '*' + getListValueWithKey(this.accCardTypeList, Spec.AccCardType)}`;
const NGPU = `${Spec.ComputeResource}:${Spec.AccCardsNum + '*' + getListValueWithKey(this.accCardTypeList, Spec.AccCardType)}`;
const statusStr = Spec.Status != '2' ? `<span style="color:rgb(245, 34, 45)">(${getListValueWithKey(this.statusList, Spec.Status.toString())})</span>` : '';
specsList.push({
k: Spec.ID,
v: `${NGPU}, CPU:${Spec.CpuCores}, ${this.$t('resourcesManagement.gpuMem')}:${Spec.GPUMemGiB}GB, ${this.$t('resourcesManagement.mem')}:${Spec.MemGiB}GB, ${this.$t('resourcesManagement.shareMem')}:${Spec.ShareMemGiB}GB, ${this.$t('resourcesManagement.unitPrice')}:${Spec.UnitPrice}${this.$t('resourcesManagement.point_hr')}`,
v: `${NGPU}, CPU:${Spec.CpuCores}, ${this.$t('resourcesManagement.gpuMem')}:${Spec.GPUMemGiB}GB, ${this.$t('resourcesManagement.mem')}:${Spec.MemGiB}GB, ${this.$t('resourcesManagement.shareMem')}:${Spec.ShareMemGiB}GB, ${this.$t('resourcesManagement.unitPrice')}:${Spec.UnitPrice}${this.$t('resourcesManagement.point_hr')}${statusStr}`,
});
cluster = Spec.Cluster;
if (queueIds.indexOf(Spec.QueueId) < 0) {


+ 35
- 1
web_src/vuepages/utils/index.js View File

@@ -1,7 +1,41 @@

import { i18n } from '~/langs';
import { ACC_CARD_TYPE } from '~/const';

export const getListValueWithKey = (list, key, k = 'k', v = 'v') => {
for (let i = 0, iLen = list.length; i < iLen; i++) {
const listI = list[i];
if (listI[k] === key) return listI[v];
}
return '';
return key;
};

export const getUrlSearchParams = () => {
const params = new URLSearchParams(location.search);
const obj = {};
params.forEach((value, key) => {
obj[key] = value;
});
return obj;
};

export const transFileSize = (srcSize) => {
if (null == srcSize || srcSize == '') {
return '0 Bytes';
}
const unitArr = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
srcSize = parseFloat(srcSize);
const index = Math.floor(Math.log(srcSize) / Math.log(1024));
const size = (srcSize / Math.pow(1024, index)).toFixed(2);
return size + ' ' + unitArr[index];
};

export const renderSpecStr = (spec, showPoint) => {
if (!spec) return '';
var ngpu = `${spec.ComputeResource}: ${spec.AccCardsNum + '*' + getListValueWithKey(ACC_CARD_TYPE, spec.AccCardType)}`;
var gpuMemStr = spec.GPUMemGiB != 0 ? `${i18n.t('resourcesManagement.gpuMem')}: ${spec.GPUMemGiB}GB, ` : '';
var sharedMemStr = spec.ShareMemGiB != 0 ? `, ${i18n.t('resourcesManagement.shareMem')}: ${spec.ShareMemGiB}GB` : '';
var pointStr = showPoint ? `, ${spec.UnitPrice == 0 ? i18n.t('resourcesManagement.free') : spec.UnitPrice + i18n.t('resourcesManagement.point_hr')}` : '';
var specStr = `${ngpu}, CPU: ${spec.CpuCores}, ${gpuMemStr}${i18n.t('resourcesManagement.mem')}: ${spec.MemGiB}GB${sharedMemStr}${pointStr}`;
return specStr;
};

Loading…
Cancel
Save