@@ -180,14 +180,14 @@ type Cloudbrain struct { | |||
AiCenter string //grampus ai center: center_id+center_name | |||
TrainUrl string //输出模型的obs路径 | |||
BranchName string //分支名称 | |||
BranchName string `xorm:"varchar(2550)"` //分支名称 | |||
Parameters string //传给modelarts的param参数 | |||
BootFile string //启动文件 | |||
BootFile string `xorm:"varchar(2550)"` //启动文件 | |||
DataUrl string `xorm:"varchar(3500)"` //数据集的obs路径 | |||
LogUrl string //日志输出的obs路径 | |||
PreVersionId int64 //父版本的版本id | |||
FlavorCode string //modelarts上的规格id | |||
Description string `xorm:"varchar(256)"` //描述 | |||
Description string `xorm:"varchar(2550)"` //描述 | |||
WorkServerNumber int //节点数 | |||
FlavorName string //规格名称 | |||
EngineName string //引擎名称 | |||
@@ -1,6 +1,7 @@ | |||
package models | |||
import ( | |||
"encoding/json" | |||
"fmt" | |||
"time" | |||
@@ -450,15 +451,30 @@ func QueryUserLoginInfo(userIds []int64) []*UserLoginLog { | |||
return loginList | |||
} | |||
var WeekBonusData = make(map[int64][]int) | |||
func QueryUserAnnualReport(userId int64) *UserSummaryCurrentYear { | |||
statictisSess := xStatistic.NewSession() | |||
defer statictisSess.Close() | |||
log.Info("userId=" + fmt.Sprint(userId)) | |||
if len(WeekBonusData) == 0 { | |||
WeekBonusData = getBonusWeekDataMap() | |||
} | |||
reList := make([]*UserSummaryCurrentYear, 0) | |||
err := statictisSess.Select("*").Table(new(UserSummaryCurrentYear)).Where("id=" + fmt.Sprint(userId)).Find(&reList) | |||
if err == nil { | |||
if len(reList) > 0 { | |||
record, ok := WeekBonusData[userId] | |||
if ok { | |||
bonusInfo := make(map[string]int) | |||
bonusInfo["order"] = record[0] | |||
bonusInfo["money"] = record[1] | |||
bonusInfo["week"] = record[2] | |||
bonusInfo["num"] = record[3] | |||
bonusInfoJson, _ := json.Marshal(bonusInfo) | |||
reList[0].WeekBonusData = string(bonusInfoJson) | |||
} | |||
return reList[0] | |||
} | |||
} else { | |||
@@ -880,6 +880,68 @@ func isUserYearData(tableName string) bool { | |||
return false | |||
} | |||
func getBonusWeekDataMap() map[int64][]int { | |||
bonusMap := make(map[int64][]int) | |||
url := setting.RecommentRepoAddr + "bonus/weekdata/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/weekdata/" + 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) < 4 { | |||
continue | |||
} | |||
userId := getInt64Value(aLine[0]) | |||
order := getIntValue(aLine[2]) | |||
money := getIntValue(aLine[3]) | |||
week, num := getWeekAndNum(filenames[i]) | |||
//email := lines[2] | |||
record, ok := bonusMap[userId] | |||
if !ok { | |||
record = make([]int, 4) | |||
record[0] = order | |||
record[1] = money | |||
record[2] = week | |||
record[3] = num | |||
bonusMap[userId] = record | |||
} else { | |||
if record[0] > order { | |||
record[0] = order | |||
record[1] = money | |||
record[2] = week | |||
record[3] = num | |||
} else { | |||
if record[0] == order && record[1] < money { | |||
record[1] = money | |||
record[2] = week | |||
record[3] = num | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
return bonusMap | |||
} | |||
func getWeekAndNum(name string) (int, int) { | |||
name = name[0 : len(name)-4] | |||
tmp := strings.Split(name, "_") | |||
if len(tmp) == 2 { | |||
week := getIntValue(tmp[0]) | |||
num := getIntValue(tmp[1]) | |||
return week, num | |||
} | |||
return 0, 0 | |||
} | |||
func getBonusMap() map[string]map[string]int { | |||
bonusMap := make(map[string]map[string]int) | |||
url := setting.RecommentRepoAddr + "bonus/record.txt" | |||
@@ -923,6 +985,14 @@ func getIntValue(val string) int { | |||
return 0 | |||
} | |||
func getInt64Value(val string) int64 { | |||
i, err := strconv.ParseInt(val, 10, 64) | |||
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] | |||
@@ -18,9 +18,9 @@ type UserSummaryCurrentYear struct { | |||
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)"` | |||
PlayARoll string `xorm:"varchar(500)"` //你参加了XX 次“我为开源打榜狂”活动,累计上榜XX 次,总共获得了社区XXX 元的激励 | |||
WeekBonusData string `xorm:"-"` | |||
Label string `xorm:"varchar(500)"` | |||
} | |||
type UserBusinessAnalysisCurrentYear struct { | |||
@@ -614,7 +614,7 @@ func ObsCreateObject(path string) error { | |||
return nil | |||
} | |||
func GetObsLogFileName(prefix string) (string, error) { | |||
func GetObsLogFileName(prefix string) ([]FileInfo, error) { | |||
input := &obs.ListObjectsInput{} | |||
input.Bucket = setting.Bucket | |||
input.Prefix = prefix | |||
@@ -622,10 +622,26 @@ func GetObsLogFileName(prefix string) (string, error) { | |||
output, err := ObsCli.ListObjects(input) | |||
if err != nil { | |||
log.Error("PutObject failed:", err.Error()) | |||
return "", err | |||
return nil, err | |||
} | |||
if output == nil || len(output.Contents) == 0 { | |||
return "", errors.New("obs log files not exist") | |||
return nil, errors.New("obs log files not exist") | |||
} | |||
fileInfos := make([]FileInfo, 0) | |||
for _, val := range output.Contents { | |||
//result[num] = c.Key | |||
if strings.HasSuffix(val.Key, ".log") { | |||
log.Info("log fileName=" + val.Key) | |||
fileInfo := FileInfo{ | |||
ModTime: val.LastModified.Local().Format("2006-01-02 15:04:05"), | |||
FileName: val.Key[len(prefix)-3:], //加上 job | |||
Size: val.Size, | |||
IsDir: false, | |||
ParenDir: prefix[0 : len(prefix)-3], | |||
} | |||
fileInfos = append(fileInfos, fileInfo) | |||
} | |||
} | |||
return output.Contents[0].Key, nil | |||
return fileInfos, nil | |||
} |
@@ -1063,6 +1063,8 @@ model_rename=Duplicate model name, please modify model name. | |||
notebook_file_not_exist=Notebook file does not exist. | |||
notebook_select_wrong=Please select a Notebook(.ipynb) file first. | |||
notebook_path_too_long=The total length of selected file or files path exceed 255 characters, please select a shorter path file or change the file path. | |||
notebook_branch_name_too_long=The total length of branch or branches name exceed 255 characters, please select a file in other branch. | |||
notebook_file_no_right=You have no right to access the Notebook(.ipynb) file. | |||
notebook_repo_conflict=The files in different branches of the same repository can not run together. | |||
debug_again_fail=Fail to restart debug task, please try again later. | |||
@@ -1062,6 +1062,8 @@ model_rename=模型名称重复,请修改模型名称 | |||
notebook_file_not_exist=Notebook文件不存在。 | |||
notebook_select_wrong=请先选择Notebook(.ipynb)文件。 | |||
notebook_path_too_long=选择的一个或多个Notebook文件路径总长度超过255个字符,请选择路径较短的文件或调整文件路径。 | |||
notebook_branch_name_too_long=选择的一个或多个Notebook文件分支名总长度超过255个字符,请选择其他分支的文件。 | |||
notebook_file_no_right=您没有这个Notebook文件的读权限。 | |||
notebook_repo_conflict=同一个仓库的不同分支文件不能同时运行。 | |||
debug_again_fail=再次调试失败,请稍后再试。 | |||
@@ -1,22 +1,67 @@ | |||
package repo | |||
import ( | |||
"net/http" | |||
"code.gitea.io/gitea/modules/log" | |||
"code.gitea.io/gitea/models" | |||
"code.gitea.io/gitea/modules/context" | |||
routeRepo "code.gitea.io/gitea/routers/repo" | |||
) | |||
func GetSuccessChunks(ctx *context.APIContext) { | |||
if errStr := checkDatasetPermission(ctx); errStr != "" { | |||
ctx.JSON(http.StatusForbidden, ctx.Tr(errStr)) | |||
} | |||
routeRepo.GetSuccessChunks(ctx.Context) | |||
} | |||
func checkDatasetPermission(ctx *context.APIContext) string { | |||
datasetId := ctx.QueryInt64("dataset_id") | |||
dataset, err := models.GetDatasetByID(datasetId) | |||
if err != nil { | |||
log.Warn("can not find dataset", err) | |||
return "dataset.query_dataset_fail" | |||
} | |||
repo, err := models.GetRepositoryByID(dataset.RepoID) | |||
if err != nil { | |||
log.Warn("can not find repo", err) | |||
return "dataset.query_dataset_fail" | |||
} | |||
permission, err := models.GetUserRepoPermission(repo, ctx.User) | |||
if err != nil { | |||
log.Warn("can not find repo permission for user", err) | |||
return "dataset.query_dataset_fail" | |||
} | |||
if !permission.CanWrite(models.UnitTypeDatasets) { | |||
return "error.no_right" | |||
} | |||
return "" | |||
} | |||
func NewMultipart(ctx *context.APIContext) { | |||
if errStr := checkDatasetPermission(ctx); errStr != "" { | |||
ctx.JSON(http.StatusForbidden, ctx.Tr(errStr)) | |||
} | |||
routeRepo.NewMultipart(ctx.Context) | |||
} | |||
func GetMultipartUploadUrl(ctx *context.APIContext) { | |||
if errStr := checkDatasetPermission(ctx); errStr != "" { | |||
ctx.JSON(http.StatusForbidden, ctx.Tr(errStr)) | |||
} | |||
routeRepo.GetMultipartUploadUrl(ctx.Context) | |||
} | |||
func CompleteMultipart(ctx *context.APIContext) { | |||
if errStr := checkDatasetPermission(ctx); errStr != "" { | |||
ctx.JSON(http.StatusForbidden, ctx.Tr(errStr)) | |||
} | |||
routeRepo.CompleteMultipart(ctx.Context) | |||
} | |||
@@ -483,7 +483,7 @@ func getFileUrl(url string, filename string) string { | |||
} | |||
} | |||
return url + middle + filename | |||
return url + middle + filename + "?reset" | |||
} | |||
func NotebookRestart(ctx *context.Context) { | |||
@@ -2893,15 +2893,19 @@ func TrainJobDownloadLogFile(ctx *context.Context) { | |||
ctx.ServerError("GetObsLogFileName", err) | |||
return | |||
} | |||
url, err := storage.GetObsCreateSignedUrlByBucketAndKey(setting.Bucket, key) | |||
if err != nil { | |||
log.Error("GetObsCreateSignedUrlByBucketAndKey failed: %v", err.Error(), ctx.Data["msgID"]) | |||
ctx.ServerError("GetObsCreateSignedUrlByBucketAndKey", err) | |||
return | |||
if len(key) > 1 { | |||
ObsDownloadManyFile(prefix[0:len(prefix)-3], ctx, task.DisplayJobName+".zip", key) | |||
} else { | |||
url, err := storage.GetObsCreateSignedUrlByBucketAndKey(setting.Bucket, key[0].ParenDir+key[0].FileName) | |||
if err != nil { | |||
log.Error("GetObsCreateSignedUrlByBucketAndKey failed: %v", err.Error(), ctx.Data["msgID"]) | |||
ctx.ServerError("GetObsCreateSignedUrlByBucketAndKey", err) | |||
return | |||
} | |||
ctx.Resp.Header().Set("Cache-Control", "max-age=0") | |||
http.Redirect(ctx.Resp, ctx.Req.Request, url, http.StatusTemporaryRedirect) | |||
} | |||
ctx.Resp.Header().Set("Cache-Control", "max-age=0") | |||
http.Redirect(ctx.Resp, ctx.Req.Request, url, http.StatusTemporaryRedirect) | |||
} | |||
func getDatasUrlListByUUIDS(uuidStr string) ([]models.Datasurl, string, string, bool, error) { | |||
var isMultiDataset bool | |||
@@ -35,6 +35,7 @@ const NoteBookExtension = ".ipynb" | |||
const CPUType = 0 | |||
const GPUType = 1 | |||
const NPUType = 2 | |||
const CharacterLength = 2550 | |||
func FileNotebookCreate(ctx *context.Context, option api.CreateFileNotebookJobOption) { | |||
@@ -46,6 +47,14 @@ func FileNotebookCreate(ctx *context.Context, option api.CreateFileNotebookJobOp | |||
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.notebook_select_wrong"))) | |||
return | |||
} | |||
if len(getBootFile(option.File, option.OwnerName, option.ProjectName)) > CharacterLength { | |||
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.notebook_path_too_long"))) | |||
return | |||
} | |||
if len(option.BranchName) > CharacterLength { | |||
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.notebook_branch_name_too_long"))) | |||
return | |||
} | |||
isNotebookFileExist, _ := isNoteBookFileExist(ctx, option) | |||
if !isNotebookFileExist { | |||
@@ -105,14 +114,29 @@ func FileNotebookCreate(ctx *context.Context, option api.CreateFileNotebookJobOp | |||
err = downloadCode(sourceRepo, getCodePath(noteBook.JobName, sourceRepo), option.BranchName) | |||
if err != nil { | |||
log.Error("download code failed", err) | |||
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("cloudbrain.load_code_failed"))) | |||
return | |||
if !strings.Contains(err.Error(), "already exists and is not an empty directory") { | |||
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("cloudbrain.load_code_failed"))) | |||
return | |||
} | |||
} | |||
} | |||
if !isRepoFileMatch(option, noteBook) { | |||
noteBook.BootFile += ";" + getBootFile(option.File, option.OwnerName, option.ProjectName) | |||
noteBook.BranchName += ";" + option.BranchName | |||
noteBook.Description += ";" + getDescription(option) | |||
if len(noteBook.BootFile)+len(getBootFile(option.File, option.OwnerName, option.ProjectName))+1 <= CharacterLength { | |||
noteBook.BootFile += ";" + getBootFile(option.File, option.OwnerName, option.ProjectName) | |||
} else { | |||
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.notebook_path_too_long"))) | |||
return | |||
} | |||
if len(noteBook.BranchName)+len(option.BranchName)+1 <= CharacterLength { | |||
noteBook.BranchName += ";" + option.BranchName | |||
} else { | |||
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.notebook_branch_name_too_long"))) | |||
return | |||
} | |||
if len(noteBook.Description)+len(getDescription(option))+1 <= CharacterLength { | |||
noteBook.Description += ";" + getDescription(option) | |||
} | |||
err := models.UpdateJob(noteBook) | |||
if err != nil { | |||
@@ -431,7 +455,11 @@ func getCodePath(jobName string, repo *models.Repository) string { | |||
} | |||
func getDescription(option api.CreateFileNotebookJobOption) string { | |||
return option.OwnerName + "/" + option.ProjectName + "/" + option.File | |||
des := option.OwnerName + "/" + option.ProjectName + "/" + option.File | |||
if len(des) <= CharacterLength { | |||
return des | |||
} | |||
return "" | |||
} | |||
func modelartsFileNoteBookCreate(ctx *context.Context, option api.CreateFileNotebookJobOption, repo *models.Repository, sourceRepo *models.Repository) { | |||