@@ -2,7 +2,7 @@ | |||
<h1><img src="public/img/favicon.png" alt="logo" width="30" height="30">AiForge - 启智AI开发协作平台</h1> | |||
[](https://git.openi.org.cn/OpenI/aiforge/releases/latest) | |||
[](https://openi.pcl.ac.cn/OpenI/aiforge/releases/latest) | |||
[](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模型开发流水线,包括代码协同开发、数据管理、模型调试、训练、推理和部署等(*目前尚未支持模型部署*)。在不同的开发阶段,我们还将提供丰富的开发工具供用户使用,如数据标注、数据筛选、模型转换、模型压缩、代码检测等。我们也欢迎社区提供更多丰富的工具接入,提高利用平台进行开发的效率。 | |||
 | |||
## 在线服务使用 | |||
本项目的在线服务平台的详细使用帮助文档,可参阅本项目[百科](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 |
@@ -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) | |||
@@ -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 { | |||
@@ -291,6 +291,13 @@ 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 | |||
@@ -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 | |||
} |
@@ -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"} | |||
@@ -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 { | |||
@@ -233,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 { | |||
@@ -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 | |||
} |
@@ -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"` | |||
} |
@@ -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() | |||
@@ -1454,7 +1454,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("") | |||
@@ -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 | |||
@@ -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 { | |||
@@ -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 | |||
@@ -1268,12 +1268,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 | |||
@@ -1283,12 +1283,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=选择训练任务 | |||
@@ -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) | |||
@@ -1012,7 +1012,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) | |||
@@ -1049,6 +1051,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) | |||
}) | |||
}) | |||
@@ -634,7 +634,7 @@ func CloudbrainGetLog(ctx *context.APIContext) { | |||
endLine += 1 | |||
} | |||
} | |||
result = getLogFromModelDir(job.JobName, startLine, endLine, resultPath) | |||
if result == nil { | |||
log.Error("GetJobLog failed: %v", err, ctx.Data["MsgID"]) | |||
@@ -649,14 +649,20 @@ func CloudbrainGetLog(ctx *context.APIContext) { | |||
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) | |||
@@ -280,15 +280,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{}{ | |||
@@ -298,11 +289,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)) | |||
@@ -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) | |||
} | |||
} |
@@ -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 { | |||
@@ -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) | |||
} |
@@ -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 | |||
} | |||
@@ -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", | |||
}) | |||
} |
@@ -940,15 +940,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, | |||
@@ -958,6 +957,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 | |||
@@ -729,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) | |||
@@ -1229,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) | |||
@@ -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) | |||
@@ -138,6 +138,7 @@ func GetResourceSpecificationList(opts models.SearchResourceSpecificationOptions | |||
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 | |||
@@ -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}} | |||
@@ -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}} | |||
@@ -284,10 +284,7 @@ | |||
<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> | |||
@@ -504,25 +501,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" | |||
@@ -712,7 +690,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,66 +908,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; | |||
@@ -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}}"> | |||
@@ -565,6 +563,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"> | |||
<input type="hidden" name="modelback{{.VersionName}}" value="-1"> | |||
@@ -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, | |||
@@ -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" .}} |
@@ -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" .}} |
@@ -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> </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"}}  </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"}}  </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,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"> {{$.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"> {{$.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"> {{$.i18n.Tr "repo.platform_instructions2"}} </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> |
@@ -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> |
@@ -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,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"> | |||
@@ -398,7 +398,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"); | |||
@@ -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", | |||
}, | |||
}; |
@@ -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 ![ | |||
@@ -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), | |||
}); | |||
}; |
@@ -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' }]; |
@@ -193,6 +193,67 @@ const en = { | |||
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', | |||
limitFilesUpload:'Only jpg/jpeg/png files can be uploaded', | |||
limitSizeUpload:'The size of the uploaded file cannot exceed 20M!', | |||
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', | |||
}, | |||
} | |||
export default en; |
@@ -193,6 +193,67 @@ const zh = { | |||
dataDesensitizationModelDesc:'利用人工智能AI技术,把图片中的人脸、车牌号码进行脱敏处理。该模型更多信息请访问项目', | |||
limitFilesUpload:'只能上传 jpg/jpeg/png 格式的文件', | |||
limitSizeUpload:'上传文件大小不能超过 20M !', | |||
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; |
@@ -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> |
@@ -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'); |
@@ -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> |
@@ -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> |
@@ -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'); |
@@ -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'); |
@@ -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; | |||
}; |