@@ -1,13 +1,19 @@ | |||||
package modelarts | package modelarts | ||||
import ( | import ( | ||||
"encoding/base64" | |||||
"encoding/json" | "encoding/json" | ||||
"errors" | "errors" | ||||
"fmt" | "fmt" | ||||
"io/ioutil" | |||||
"net/http" | |||||
"os" | |||||
"path" | "path" | ||||
"strconv" | "strconv" | ||||
"strings" | "strings" | ||||
"code.gitea.io/gitea/modules/cloudbrain" | |||||
"code.gitea.io/gitea/modules/modelarts_cd" | "code.gitea.io/gitea/modules/modelarts_cd" | ||||
"code.gitea.io/gitea/models" | "code.gitea.io/gitea/models" | ||||
@@ -276,7 +282,7 @@ func GenerateTask(ctx *context.Context, jobName, uuid, description, flavor strin | |||||
return nil | return nil | ||||
} | } | ||||
func GenerateNotebook2(ctx *context.Context, displayJobName, jobName, uuid, description, imageId string, spec *models.Specification) error { | |||||
func GenerateNotebook2(ctx *context.Context, displayJobName, jobName, uuid, description, imageId string, spec *models.Specification, bootFile string) (string, error) { | |||||
if poolInfos == nil { | if poolInfos == nil { | ||||
json.Unmarshal([]byte(setting.PoolInfos), &poolInfos) | json.Unmarshal([]byte(setting.PoolInfos), &poolInfos) | ||||
} | } | ||||
@@ -284,7 +290,7 @@ func GenerateNotebook2(ctx *context.Context, displayJobName, jobName, uuid, desc | |||||
imageName, err := GetNotebookImageName(imageId) | imageName, err := GetNotebookImageName(imageId) | ||||
if err != nil { | if err != nil { | ||||
log.Error("GetNotebookImageName failed: %v", err.Error()) | log.Error("GetNotebookImageName failed: %v", err.Error()) | ||||
return err | |||||
return "", err | |||||
} | } | ||||
createTime := timeutil.TimeStampNow() | createTime := timeutil.TimeStampNow() | ||||
jobResult, err := createNotebook2(models.CreateNotebook2Params{ | jobResult, err := createNotebook2(models.CreateNotebook2Params{ | ||||
@@ -316,10 +322,10 @@ func GenerateNotebook2(ctx *context.Context, displayJobName, jobName, uuid, desc | |||||
}) | }) | ||||
if errTemp != nil { | if errTemp != nil { | ||||
log.Error("InsertCloudbrainTemp failed: %v", errTemp.Error()) | log.Error("InsertCloudbrainTemp failed: %v", errTemp.Error()) | ||||
return errTemp | |||||
return "", errTemp | |||||
} | } | ||||
} | } | ||||
return err | |||||
return "", err | |||||
} | } | ||||
task := &models.Cloudbrain{ | task := &models.Cloudbrain{ | ||||
Status: jobResult.Status, | Status: jobResult.Status, | ||||
@@ -334,6 +340,7 @@ func GenerateNotebook2(ctx *context.Context, displayJobName, jobName, uuid, desc | |||||
Uuid: uuid, | Uuid: uuid, | ||||
ComputeResource: models.NPUResource, | ComputeResource: models.NPUResource, | ||||
Image: imageName, | Image: imageName, | ||||
BootFile: bootFile, | |||||
Description: description, | Description: description, | ||||
CreatedUnix: createTime, | CreatedUnix: createTime, | ||||
UpdatedUnix: createTime, | UpdatedUnix: createTime, | ||||
@@ -342,12 +349,12 @@ func GenerateNotebook2(ctx *context.Context, displayJobName, jobName, uuid, desc | |||||
err = models.CreateCloudbrain(task) | err = models.CreateCloudbrain(task) | ||||
if err != nil { | if err != nil { | ||||
return err | |||||
return "", err | |||||
} | } | ||||
stringId := strconv.FormatInt(task.ID, 10) | stringId := strconv.FormatInt(task.ID, 10) | ||||
notification.NotifyOtherTask(ctx.User, ctx.Repo.Repository, stringId, displayJobName, models.ActionCreateDebugNPUTask) | notification.NotifyOtherTask(ctx.User, ctx.Repo.Repository, stringId, displayJobName, models.ActionCreateDebugNPUTask) | ||||
return nil | |||||
return jobResult.ID, nil | |||||
} | } | ||||
func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (jobId string, err error) { | func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (jobId string, err error) { | ||||
@@ -907,6 +914,11 @@ func HandleNotebookInfo(task *models.Cloudbrain) error { | |||||
if task.FlavorCode == "" { | if task.FlavorCode == "" { | ||||
task.FlavorCode = result.Flavor | task.FlavorCode = result.Flavor | ||||
} | } | ||||
if oldStatus != task.Status && task.Status == string(models.ModelArtsRunning) && task.BootFile != "" { | |||||
uploadNoteBookFile(task, result) | |||||
} | |||||
err = models.UpdateJob(task) | err = models.UpdateJob(task) | ||||
if err != nil { | if err != nil { | ||||
log.Error("UpdateJob(%s) failed:%v", task.DisplayJobName, err) | log.Error("UpdateJob(%s) failed:%v", task.DisplayJobName, err) | ||||
@@ -917,6 +929,51 @@ func HandleNotebookInfo(task *models.Cloudbrain) error { | |||||
return nil | return nil | ||||
} | } | ||||
func uploadNoteBookFile(task *models.Cloudbrain, result *models.GetNotebook2Result) { | |||||
jupyterUrl := result.Url + "?token=" + result.Token | |||||
client := getRestyClient() | |||||
res, err := client.R().Get(jupyterUrl) | |||||
codePath := setting.JobPath + task.JobName + cloudbrain.CodeMountPath | |||||
if err != nil { | |||||
log.Error("browser jupyterUrl failed:%v", task.DisplayJobName, err) | |||||
} else { | |||||
cookies := res.Cookies() | |||||
xsrf := "" | |||||
for _, cookie := range cookies { | |||||
if cookie.Name == "_xsrf" { | |||||
xsrf = cookie.Value | |||||
} | |||||
} | |||||
fileContents, err := ioutil.ReadFile(codePath + "/" + task.BootFile) | |||||
if err != nil { | |||||
log.Error("read jupyter file failed:%v", task.DisplayJobName, err) | |||||
} | |||||
base64Content := base64.StdEncoding.EncodeToString(fileContents) | |||||
uploadUrl := result.Url + "/api/contents/" + path.Base(task.BootFile) | |||||
res, err = client.R(). | |||||
SetCookies(cookies). | |||||
SetHeader("X-XSRFToken", xsrf). | |||||
SetBody(map[string]interface{}{ | |||||
"type": "file", | |||||
"format": "base64", | |||||
"name": path.Base(task.BootFile), | |||||
"path": path.Base(task.BootFile), | |||||
"content": base64Content}). | |||||
Put(uploadUrl) | |||||
if err != nil { | |||||
log.Error("upload jupyter file failed:%v", task.DisplayJobName, err) | |||||
} else if res.StatusCode() != http.StatusCreated { | |||||
log.Error("upload jupyter file failed:%v", task.DisplayJobName, err) | |||||
} | |||||
} | |||||
go os.RemoveAll(codePath) | |||||
} | |||||
func SyncTempStatusJob() { | func SyncTempStatusJob() { | ||||
jobs, err := models.GetCloudBrainTempJobs() | jobs, err := models.GetCloudBrainTempJobs() | ||||
if err != nil { | if err != nil { | ||||
@@ -88,11 +88,11 @@ type Parameters struct { | |||||
} `json:"parameter"` | } `json:"parameter"` | ||||
} | } | ||||
func GenerateNotebook(ctx *context.Context, displayJobName, jobName, uuid, description, imageId string, spec *models.Specification) error { | |||||
func GenerateNotebook(ctx *context.Context, displayJobName, jobName, uuid, description, imageId string, spec *models.Specification, bootFile string) (string, error) { | |||||
imageName, err := GetNotebookImageName(imageId) | imageName, err := GetNotebookImageName(imageId) | ||||
if err != nil { | if err != nil { | ||||
log.Error("GetNotebookImageName failed: %v", err.Error()) | log.Error("GetNotebookImageName failed: %v", err.Error()) | ||||
return err | |||||
return "", err | |||||
} | } | ||||
createTime := timeutil.TimeStampNow() | createTime := timeutil.TimeStampNow() | ||||
jobResult, err := createNotebook(models.CreateNotebookWithoutPoolParams{ | jobResult, err := createNotebook(models.CreateNotebookWithoutPoolParams{ | ||||
@@ -123,10 +123,10 @@ func GenerateNotebook(ctx *context.Context, displayJobName, jobName, uuid, descr | |||||
}) | }) | ||||
if errTemp != nil { | if errTemp != nil { | ||||
log.Error("InsertCloudbrainTemp failed: %v", errTemp.Error()) | log.Error("InsertCloudbrainTemp failed: %v", errTemp.Error()) | ||||
return errTemp | |||||
return "", errTemp | |||||
} | } | ||||
} | } | ||||
return err | |||||
return "", err | |||||
} | } | ||||
task := &models.Cloudbrain{ | task := &models.Cloudbrain{ | ||||
Status: jobResult.Status, | Status: jobResult.Status, | ||||
@@ -145,16 +145,17 @@ func GenerateNotebook(ctx *context.Context, displayJobName, jobName, uuid, descr | |||||
CreatedUnix: createTime, | CreatedUnix: createTime, | ||||
UpdatedUnix: createTime, | UpdatedUnix: createTime, | ||||
Spec: spec, | Spec: spec, | ||||
BootFile: bootFile, | |||||
} | } | ||||
err = models.CreateCloudbrain(task) | err = models.CreateCloudbrain(task) | ||||
if err != nil { | if err != nil { | ||||
return err | |||||
return "", err | |||||
} | } | ||||
stringId := strconv.FormatInt(task.ID, 10) | stringId := strconv.FormatInt(task.ID, 10) | ||||
notification.NotifyOtherTask(ctx.User, ctx.Repo.Repository, stringId, displayJobName, models.ActionCreateDebugNPUTask) | notification.NotifyOtherTask(ctx.User, ctx.Repo.Repository, stringId, displayJobName, models.ActionCreateDebugNPUTask) | ||||
return nil | |||||
return jobResult.ID, nil | |||||
} | } | ||||
func GetNotebookImageName(imageId string) (string, error) { | func GetNotebookImageName(imageId string) (string, error) { | ||||
@@ -175,41 +176,3 @@ func GetNotebookImageName(imageId string) (string, error) { | |||||
return imageName, nil | return imageName, nil | ||||
} | } | ||||
/* | |||||
func HandleNotebookInfo(task *models.Cloudbrain) error { | |||||
result, err := GetNotebook(task.JobID) | |||||
if err != nil { | |||||
log.Error("GetNotebook2(%s) failed:%v", task.DisplayJobName, err) | |||||
return err | |||||
} | |||||
if result != nil { | |||||
oldStatus := task.Status | |||||
task.Status = result.Status | |||||
if task.StartTime == 0 && result.Lease.UpdateTime > 0 { | |||||
task.StartTime = timeutil.TimeStamp(result.Lease.UpdateTime / 1000) | |||||
} | |||||
if task.EndTime == 0 && models.IsModelArtsDebugJobTerminal(task.Status) { | |||||
task.EndTime = timeutil.TimeStampNow() | |||||
} | |||||
task.CorrectCreateUnix() | |||||
task.ComputeAndSetDuration() | |||||
if oldStatus != task.Status { | |||||
notification.NotifyChangeCloudbrainStatus(task, oldStatus) | |||||
} | |||||
if task.FlavorCode == "" { | |||||
task.FlavorCode = result.Flavor | |||||
} | |||||
err = models.UpdateJob(task) | |||||
if err != nil { | |||||
log.Error("UpdateJob(%s) failed:%v", task.DisplayJobName, err) | |||||
return err | |||||
} | |||||
} | |||||
return nil | |||||
} | |||||
*/ |
@@ -609,9 +609,9 @@ var ( | |||||
AiCenterInfo string | AiCenterInfo string | ||||
}{} | }{} | ||||
C2NetInfos *C2NetSqInfos | |||||
CenterInfos *AiCenterInfos | |||||
C2NetMapInfo map[string]*C2NetSequenceInfo | |||||
C2NetInfos *C2NetSqInfos | |||||
CenterInfos *AiCenterInfos | |||||
C2NetMapInfo map[string]*C2NetSequenceInfo | |||||
//elk config | //elk config | ||||
ElkUrl string | ElkUrl string | ||||
@@ -712,6 +712,16 @@ var ( | |||||
TeamName string | TeamName string | ||||
}{} | }{} | ||||
FileNoteBook = struct { | |||||
ProjectName string | |||||
ImageGPU string | |||||
SpecIdGPU int64 | |||||
SpecIdCPU int64 | |||||
ImageIdNPU string | |||||
ImageNPU string | |||||
SpecIdNPU int64 | |||||
}{} | |||||
ModelConvert = struct { | ModelConvert = struct { | ||||
GPU_PYTORCH_IMAGE string | GPU_PYTORCH_IMAGE string | ||||
GpuQueue string | GpuQueue string | ||||
@@ -1655,9 +1665,9 @@ func getGrampusConfig() { | |||||
if err := json.Unmarshal([]byte(Grampus.C2NetSequence), &C2NetInfos); err != nil { | if err := json.Unmarshal([]byte(Grampus.C2NetSequence), &C2NetInfos); err != nil { | ||||
log.Error("Unmarshal(C2NetSequence) failed:%v", err) | log.Error("Unmarshal(C2NetSequence) failed:%v", err) | ||||
} | } | ||||
C2NetMapInfo=make(map[string]*C2NetSequenceInfo) | |||||
for _,value :=range C2NetInfos.C2NetSqInfo{ | |||||
C2NetMapInfo[value.Name]=value | |||||
C2NetMapInfo = make(map[string]*C2NetSequenceInfo) | |||||
for _, value := range C2NetInfos.C2NetSqInfo { | |||||
C2NetMapInfo[value.Name] = value | |||||
} | } | ||||
} | } | ||||
Grampus.SyncScriptProject = sec.Key("SYNC_SCRIPT_PROJECT").MustString("script_for_grampus") | Grampus.SyncScriptProject = sec.Key("SYNC_SCRIPT_PROJECT").MustString("script_for_grampus") | ||||
@@ -41,6 +41,14 @@ type CreateTrainJobOption struct { | |||||
SpecId int64 `json:"spec_id" binding:"Required"` | SpecId int64 `json:"spec_id" binding:"Required"` | ||||
} | } | ||||
type CreateFileNotebookJobOption struct { | |||||
Type int `json:"type"` //0 CPU 1 GPU 2 NPU | |||||
File string `json:"file" binding:"Required"` | |||||
BranchName string `json:"branch_name" binding:"Required"` | |||||
OwnerName string `json:"owner_name" binding:"Required"` | |||||
ProjectName string `json:"project_name" binding:"Required"` | |||||
} | |||||
type Cloudbrain struct { | type Cloudbrain struct { | ||||
ID int64 `json:"id"` | ID int64 `json:"id"` | ||||
JobID string `json:"job_id"` | JobID string `json:"job_id"` | ||||
@@ -1007,6 +1007,7 @@ readme = README | |||||
readme_helper = Select a README file template. | readme_helper = Select a README file template. | ||||
auto_init = Initialize Repository (Adds .gitignore, License and README) | auto_init = Initialize Repository (Adds .gitignore, License and README) | ||||
create_repo = Create Repository | create_repo = Create Repository | ||||
failed_to_create_repo=Failed to create repository, please try again later. | |||||
create_course = Publish Course | create_course = Publish Course | ||||
failed_to_create_course=Failed to publish course, please try again later. | failed_to_create_course=Failed to publish course, please try again later. | ||||
default_branch = Default Branch | default_branch = Default Branch | ||||
@@ -1041,6 +1042,9 @@ model_experience = Model Experience | |||||
model_noright=You have no right to do the operation. | model_noright=You have no right to do the operation. | ||||
model_rename=Duplicate model name, please modify model name. | 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. | |||||
date=Date | date=Date | ||||
repo_add=Project Increment | repo_add=Project Increment | ||||
repo_total=Project Total | repo_total=Project Total | ||||
@@ -1013,6 +1013,7 @@ readme=自述 | |||||
readme_helper=选择自述文件模板。 | readme_helper=选择自述文件模板。 | ||||
auto_init=初始化存储库 (添加. gitignore、许可证和自述文件) | auto_init=初始化存储库 (添加. gitignore、许可证和自述文件) | ||||
create_repo=创建项目 | create_repo=创建项目 | ||||
failed_to_create_repo=创建项目失败,请稍后再试。 | |||||
create_course=发布课程 | create_course=发布课程 | ||||
failed_to_create_course=发布课程失败,请稍后再试。 | failed_to_create_course=发布课程失败,请稍后再试。 | ||||
default_branch=默认分支 | default_branch=默认分支 | ||||
@@ -1041,6 +1042,8 @@ model_experience = 模型体验 | |||||
model_noright=您没有操作权限。 | model_noright=您没有操作权限。 | ||||
model_rename=模型名称重复,请修改模型名称 | model_rename=模型名称重复,请修改模型名称 | ||||
notebook_file_not_exist=Notebook文件不存在。 | |||||
notebook_select_wrong=请先选择Notebook(.ipynb)文件。 | |||||
date=日期 | date=日期 | ||||
repo_add=新增项目 | repo_add=新增项目 | ||||
@@ -736,6 +736,12 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
m.Get("/my_favorite", repo.MyFavoriteDatasetMultiple) | m.Get("/my_favorite", repo.MyFavoriteDatasetMultiple) | ||||
}, reqToken(), repoAssignment()) | }, reqToken(), repoAssignment()) | ||||
m.Group("/file_notebook", func() { | |||||
m.Post("/create", reqToken(), reqWeChat(), bind(api.CreateFileNotebookJobOption{}), repo.CreateFileNoteBook) | |||||
}) | |||||
m.Group("/repos", func() { | m.Group("/repos", func() { | ||||
m.Get("/search", repo.Search) | m.Get("/search", repo.Search) | ||||
@@ -79,6 +79,9 @@ func CloudBrainShow(ctx *context.APIContext) { | |||||
ctx.JSON(http.StatusOK, models.BaseMessageWithDataApi{Code: 0, Message: "", Data: convert.ToCloudBrain(task)}) | ctx.JSON(http.StatusOK, models.BaseMessageWithDataApi{Code: 0, Message: "", Data: convert.ToCloudBrain(task)}) | ||||
} | } | ||||
func CreateFileNoteBook(ctx *context.APIContext, option api.CreateFileNotebookJobOption) { | |||||
cloudbrainTask.FileNotebookCreate(ctx.Context, option) | |||||
} | |||||
func CreateCloudBrain(ctx *context.APIContext, option api.CreateTrainJobOption) { | func CreateCloudBrain(ctx *context.APIContext, option api.CreateTrainJobOption) { | ||||
if option.Type == cloudbrainTask.TaskTypeCloudbrainOne { | if option.Type == cloudbrainTask.TaskTypeCloudbrainOne { | ||||
@@ -11,7 +11,8 @@ import ( | |||||
"os" | "os" | ||||
"strconv" | "strconv" | ||||
"strings" | "strings" | ||||
"time" | |||||
cloudbrainService "code.gitea.io/gitea/services/cloudbrain" | |||||
"code.gitea.io/gitea/models" | "code.gitea.io/gitea/models" | ||||
"code.gitea.io/gitea/modules/aisafety" | "code.gitea.io/gitea/modules/aisafety" | ||||
@@ -483,7 +484,6 @@ func isTaskNotFinished(status string) bool { | |||||
} | } | ||||
func AiSafetyCreateForGetGPU(ctx *context.Context) { | func AiSafetyCreateForGetGPU(ctx *context.Context) { | ||||
t := time.Now() | |||||
ctx.Data["PageIsCloudBrain"] = true | ctx.Data["PageIsCloudBrain"] = true | ||||
ctx.Data["IsCreate"] = true | ctx.Data["IsCreate"] = true | ||||
ctx.Data["type"] = models.TypeCloudBrainOne | ctx.Data["type"] = models.TypeCloudBrainOne | ||||
@@ -497,7 +497,7 @@ func AiSafetyCreateForGetGPU(ctx *context.Context) { | |||||
log.Info("GPUBaseDataSetUUID=" + setting.ModelSafetyTest.GPUBaseDataSetUUID) | log.Info("GPUBaseDataSetUUID=" + setting.ModelSafetyTest.GPUBaseDataSetUUID) | ||||
log.Info("GPUCombatDataSetName=" + setting.ModelSafetyTest.GPUCombatDataSetName) | log.Info("GPUCombatDataSetName=" + setting.ModelSafetyTest.GPUCombatDataSetName) | ||||
log.Info("GPUCombatDataSetUUID=" + setting.ModelSafetyTest.GPUCombatDataSetUUID) | log.Info("GPUCombatDataSetUUID=" + setting.ModelSafetyTest.GPUCombatDataSetUUID) | ||||
var displayJobName = jobNamePrefixValid(cutString(ctx.User.Name, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:] | |||||
var displayJobName = cloudbrainService.GetDisplayJobName(ctx.User.Name) | |||||
ctx.Data["display_job_name"] = displayJobName | ctx.Data["display_job_name"] = displayJobName | ||||
prepareCloudbrainOneSpecs(ctx) | prepareCloudbrainOneSpecs(ctx) | ||||
queuesDetail, _ := cloudbrain.GetQueuesDetail() | queuesDetail, _ := cloudbrain.GetQueuesDetail() | ||||
@@ -514,12 +514,11 @@ func AiSafetyCreateForGetGPU(ctx *context.Context) { | |||||
} | } | ||||
func AiSafetyCreateForGetNPU(ctx *context.Context) { | func AiSafetyCreateForGetNPU(ctx *context.Context) { | ||||
t := time.Now() | |||||
ctx.Data["PageIsCloudBrain"] = true | ctx.Data["PageIsCloudBrain"] = true | ||||
ctx.Data["IsCreate"] = true | ctx.Data["IsCreate"] = true | ||||
ctx.Data["type"] = models.TypeCloudBrainTwo | ctx.Data["type"] = models.TypeCloudBrainTwo | ||||
ctx.Data["compute_resource"] = models.NPUResource | ctx.Data["compute_resource"] = models.NPUResource | ||||
var displayJobName = jobNamePrefixValid(cutString(ctx.User.Name, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:] | |||||
var displayJobName = cloudbrainService.GetDisplayJobName(ctx.User.Name) | |||||
ctx.Data["display_job_name"] = displayJobName | ctx.Data["display_job_name"] = displayJobName | ||||
ctx.Data["datasetType"] = models.TypeCloudBrainTwo | ctx.Data["datasetType"] = models.TypeCloudBrainTwo | ||||
ctx.Data["BaseDataSetName"] = setting.ModelSafetyTest.NPUBaseDataSetName | ctx.Data["BaseDataSetName"] = setting.ModelSafetyTest.NPUBaseDataSetName | ||||
@@ -2,7 +2,6 @@ package repo | |||||
import ( | import ( | ||||
"bufio" | "bufio" | ||||
"code.gitea.io/gitea/modules/urfs_client/urchin" | |||||
"encoding/json" | "encoding/json" | ||||
"errors" | "errors" | ||||
"fmt" | "fmt" | ||||
@@ -16,6 +15,10 @@ import ( | |||||
"time" | "time" | ||||
"unicode/utf8" | "unicode/utf8" | ||||
cloudbrainService "code.gitea.io/gitea/services/cloudbrain" | |||||
"code.gitea.io/gitea/modules/urfs_client/urchin" | |||||
"code.gitea.io/gitea/modules/dataset" | "code.gitea.io/gitea/modules/dataset" | ||||
"code.gitea.io/gitea/services/cloudbrain/cloudbrainTask" | "code.gitea.io/gitea/services/cloudbrain/cloudbrainTask" | ||||
@@ -91,28 +94,9 @@ func MustEnableCloudbrain(ctx *context.Context) { | |||||
} | } | ||||
} | } | ||||
func cutString(str string, lens int) string { | |||||
if len(str) < lens { | |||||
return str | |||||
} | |||||
return str[:lens] | |||||
} | |||||
func jobNamePrefixValid(s string) string { | |||||
lowStr := strings.ToLower(s) | |||||
re := regexp.MustCompile(`[^a-z0-9_\\-]+`) | |||||
removeSpecial := re.ReplaceAllString(lowStr, "") | |||||
re = regexp.MustCompile(`^[_\\-]+`) | |||||
return re.ReplaceAllString(removeSpecial, "") | |||||
} | |||||
func cloudBrainNewDataPrepare(ctx *context.Context, jobType string) error { | func cloudBrainNewDataPrepare(ctx *context.Context, jobType string) error { | ||||
ctx.Data["PageIsCloudBrain"] = true | ctx.Data["PageIsCloudBrain"] = true | ||||
t := time.Now() | |||||
var displayJobName = jobNamePrefixValid(cutString(ctx.User.Name, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:] | |||||
var displayJobName = cloudbrainService.GetDisplayJobName(ctx.User.Name) | |||||
ctx.Data["display_job_name"] = displayJobName | ctx.Data["display_job_name"] = displayJobName | ||||
ctx.Data["command"] = cloudbrain.GetCloudbrainDebugCommand() | ctx.Data["command"] = cloudbrain.GetCloudbrainDebugCommand() | ||||
@@ -11,7 +11,6 @@ import ( | |||||
"path" | "path" | ||||
"strconv" | "strconv" | ||||
"strings" | "strings" | ||||
"time" | |||||
"code.gitea.io/gitea/services/cloudbrain/cloudbrainTask" | "code.gitea.io/gitea/services/cloudbrain/cloudbrainTask" | ||||
@@ -75,8 +74,7 @@ func GrampusTrainJobNPUNew(ctx *context.Context) { | |||||
func grampusTrainJobNewDataPrepare(ctx *context.Context, processType string) error { | func grampusTrainJobNewDataPrepare(ctx *context.Context, processType string) error { | ||||
ctx.Data["PageIsCloudBrain"] = true | ctx.Data["PageIsCloudBrain"] = true | ||||
t := time.Now() | |||||
var displayJobName = jobNamePrefixValid(cutString(ctx.User.Name, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:] | |||||
var displayJobName = cloudbrainService.GetDisplayJobName(ctx.User.Name) | |||||
ctx.Data["display_job_name"] = displayJobName | ctx.Data["display_job_name"] = displayJobName | ||||
//get valid images | //get valid images | ||||
@@ -15,6 +15,8 @@ import ( | |||||
"time" | "time" | ||||
"unicode/utf8" | "unicode/utf8" | ||||
cloudbrainService "code.gitea.io/gitea/services/cloudbrain" | |||||
"code.gitea.io/gitea/services/cloudbrain/cloudbrainTask" | "code.gitea.io/gitea/services/cloudbrain/cloudbrainTask" | ||||
"code.gitea.io/gitea/modules/dataset" | "code.gitea.io/gitea/modules/dataset" | ||||
@@ -128,8 +130,7 @@ func NotebookNew(ctx *context.Context) { | |||||
func notebookNewDataPrepare(ctx *context.Context) error { | func notebookNewDataPrepare(ctx *context.Context) error { | ||||
ctx.Data["PageIsCloudBrain"] = true | ctx.Data["PageIsCloudBrain"] = true | ||||
t := time.Now() | |||||
var displayJobName = jobNamePrefixValid(cutString(ctx.User.Name, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:] | |||||
var displayJobName = cloudbrainService.GetDisplayJobName(ctx.User.Name) | |||||
ctx.Data["display_job_name"] = displayJobName | ctx.Data["display_job_name"] = displayJobName | ||||
attachs, err := models.GetModelArtsUserAttachments(ctx.User.ID) | attachs, err := models.GetModelArtsUserAttachments(ctx.User.ID) | ||||
@@ -239,9 +240,9 @@ func Notebook2Create(ctx *context.Context, form auth.CreateModelArtsNotebookForm | |||||
} | } | ||||
if setting.ModelartsCD.Enabled { | if setting.ModelartsCD.Enabled { | ||||
err = modelarts_cd.GenerateNotebook(ctx, displayJobName, jobName, uuid, description, imageId, spec) | |||||
_, err = modelarts_cd.GenerateNotebook(ctx, displayJobName, jobName, uuid, description, imageId, spec, "") | |||||
} else { | } else { | ||||
err = modelarts.GenerateNotebook2(ctx, displayJobName, jobName, uuid, description, imageId, spec) | |||||
_, err = modelarts.GenerateNotebook2(ctx, displayJobName, jobName, uuid, description, imageId, spec, "") | |||||
} | } | ||||
if err != nil { | if err != nil { | ||||
@@ -714,8 +715,7 @@ func trainJobNewDataPrepare(ctx *context.Context) error { | |||||
// return | // return | ||||
//} | //} | ||||
t := time.Now() | |||||
var displayJobName = jobNamePrefixValid(cutString(ctx.User.Name, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:] | |||||
var displayJobName = cloudbrainService.GetDisplayJobName(ctx.User.Name) | |||||
ctx.Data["display_job_name"] = displayJobName | ctx.Data["display_job_name"] = displayJobName | ||||
attachs, err := models.GetModelArtsTrainAttachments(ctx.User.ID) | attachs, err := models.GetModelArtsTrainAttachments(ctx.User.ID) | ||||
@@ -2351,8 +2351,7 @@ func inferenceJobNewDataPrepare(ctx *context.Context) error { | |||||
ctx.Data["PageIsCloudBrain"] = true | ctx.Data["PageIsCloudBrain"] = true | ||||
ctx.Data["newInference"] = true | ctx.Data["newInference"] = true | ||||
t := time.Now() | |||||
var displayJobName = jobNamePrefixValid(cutString(ctx.User.Name, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:] | |||||
var displayJobName = cloudbrainService.GetDisplayJobName(ctx.User.Name) | |||||
ctx.Data["display_job_name"] = displayJobName | ctx.Data["display_job_name"] = displayJobName | ||||
attachs, err := models.GetModelArtsTrainAttachments(ctx.User.ID) | attachs, err := models.GetModelArtsTrainAttachments(ctx.User.ID) | ||||
@@ -0,0 +1,330 @@ | |||||
package cloudbrainTask | |||||
import ( | |||||
"fmt" | |||||
"net/http" | |||||
"os" | |||||
"code.gitea.io/gitea/modules/modelarts" | |||||
"code.gitea.io/gitea/modules/modelarts_cd" | |||||
"code.gitea.io/gitea/modules/git" | |||||
"code.gitea.io/gitea/modules/cloudbrain" | |||||
"code.gitea.io/gitea/modules/log" | |||||
"code.gitea.io/gitea/modules/redis/redis_key" | |||||
"code.gitea.io/gitea/modules/redis/redis_lock" | |||||
"code.gitea.io/gitea/modules/storage" | |||||
"code.gitea.io/gitea/services/cloudbrain/resource" | |||||
"code.gitea.io/gitea/services/reward/point/account" | |||||
"code.gitea.io/gitea/modules/setting" | |||||
cloudbrainService "code.gitea.io/gitea/services/cloudbrain" | |||||
repo_service "code.gitea.io/gitea/services/repository" | |||||
"code.gitea.io/gitea/models" | |||||
"code.gitea.io/gitea/modules/context" | |||||
api "code.gitea.io/gitea/modules/structs" | |||||
"code.gitea.io/gitea/modules/util" | |||||
) | |||||
func FileNotebookCreate(ctx *context.Context, option api.CreateFileNotebookJobOption) { | |||||
if ctx.Written() { | |||||
return | |||||
} | |||||
//create repo if not exist | |||||
repo, err := models.GetRepositoryByName(ctx.User.ID, setting.FileNoteBook.ProjectName) | |||||
if repo == nil { | |||||
repo, err = repo_service.CreateRepository(ctx.User, ctx.User, models.CreateRepoOptions{ | |||||
Name: setting.FileNoteBook.ProjectName, | |||||
Alias: "", | |||||
Description: "", | |||||
IssueLabels: "", | |||||
Gitignores: "", | |||||
License: "", | |||||
Readme: "Default", | |||||
IsPrivate: false, | |||||
AutoInit: true, | |||||
DefaultBranch: "master", | |||||
}) | |||||
} | |||||
if err != nil { | |||||
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi("repo.failed_to_create_repo")) | |||||
} | |||||
} | |||||
func cloudBrainFileNoteBookCreate(ctx *context.Context, option api.CreateFileNotebookJobOption, repo *models.Repository) { | |||||
displayJobName := cloudbrainService.GetDisplayJobName(ctx.User.Name) | |||||
jobName := util.ConvertDisplayJobNameToJobName(displayJobName) | |||||
jobType := string(models.JobTypeDebug) | |||||
codePath := getCodePath(jobName) | |||||
lock := redis_lock.NewDistributeLock(redis_key.CloudbrainBindingJobNameKey(fmt.Sprint(repo.ID), jobType, displayJobName)) | |||||
defer lock.UnLock() | |||||
isOk, err := lock.Lock(models.CloudbrainKeyDuration) | |||||
if !isOk { | |||||
log.Error("lock processed failed:%v", err, ctx.Data["MsgID"]) | |||||
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.cloudbrain_samejob_err"))) | |||||
return | |||||
} | |||||
tasks, err := models.GetCloudbrainsByDisplayJobName(repo.ID, jobType, displayJobName) | |||||
if err == nil { | |||||
if len(tasks) != 0 { | |||||
log.Error("the job name did already exist", ctx.Data["MsgID"]) | |||||
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.cloudbrain_samejob_err"))) | |||||
return | |||||
} | |||||
} else { | |||||
if !models.IsErrJobNotExist(err) { | |||||
log.Error("system error, %v", err, ctx.Data["MsgID"]) | |||||
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi("system error.")) | |||||
return | |||||
} | |||||
} | |||||
count, err := GetNotFinalStatusTaskCount(ctx.User.ID, models.TypeCloudBrainOne, jobType) | |||||
if err != nil { | |||||
log.Error("GetCloudbrainCountByUserID failed:%v", err, ctx.Data["MsgID"]) | |||||
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi("system error.")) | |||||
return | |||||
} else { | |||||
if count >= 1 { | |||||
log.Error("the user already has running or waiting task", ctx.Data["MsgID"]) | |||||
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.cloudbrain.morethanonejob"))) | |||||
return | |||||
} | |||||
} | |||||
repoPath := models.RepoPath(repo.OwnerName, repo.Name) | |||||
gitRepo, err := git.OpenRepository(repoPath) | |||||
if err != nil { | |||||
ctx.Error(500, "RepoRef Invalid repo "+repoPath, err.Error()) | |||||
return | |||||
} | |||||
// We opened it, we should close it | |||||
defer func() { | |||||
// If it's been set to nil then assume someone else has closed it. | |||||
if ctx.Repo.GitRepo != nil { | |||||
ctx.Repo.GitRepo.Close() | |||||
} | |||||
}() | |||||
ctx.Repo = &context.Repository{ | |||||
Repository: repo, | |||||
GitRepo: gitRepo, | |||||
} | |||||
fileExist, err := ctx.Repo.FileExists(option.File, option.BranchName) | |||||
if err != nil || !fileExist { | |||||
log.Error("Get file error:", err, ctx.Data["MsgID"]) | |||||
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.notebook_file_not_exist"))) | |||||
return | |||||
} | |||||
command := cloudbrain.GetCloudbrainDebugCommand() | |||||
errStr := uploadCodeFile(repo, codePath, option.BranchName, option.File, jobName) | |||||
if errStr != "" { | |||||
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.notebook_file_not_exist"))) | |||||
return | |||||
} | |||||
commitID, _ := ctx.Repo.GitRepo.GetBranchCommitID(option.BranchName) | |||||
specId := setting.FileNoteBook.SpecIdGPU | |||||
if option.Type == 0 { | |||||
specId = setting.FileNoteBook.SpecIdCPU | |||||
} | |||||
spec, err := resource.GetAndCheckSpec(ctx.User.ID, specId, models.FindSpecsOptions{ | |||||
JobType: models.JobType(jobType), | |||||
ComputeResource: models.GPU, | |||||
Cluster: models.OpenICluster, | |||||
AiCenterCode: models.AICenterOfCloudBrainOne}) | |||||
if err != nil || spec == nil { | |||||
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("cloudbrain.wrong_specification"))) | |||||
return | |||||
} | |||||
if !account.IsPointBalanceEnough(ctx.User.ID, spec.UnitPrice) { | |||||
log.Error("point balance is not enough,userId=%d specId=%d", ctx.User.ID, spec.ID) | |||||
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("points.insufficient_points_balance"))) | |||||
return | |||||
} | |||||
req := cloudbrain.GenerateCloudBrainTaskReq{ | |||||
Ctx: ctx, | |||||
DisplayJobName: displayJobName, | |||||
JobName: jobName, | |||||
Image: setting.FileNoteBook.ImageGPU, | |||||
Command: command, | |||||
Uuids: "", | |||||
DatasetNames: "", | |||||
DatasetInfos: nil, | |||||
CodePath: storage.GetMinioPath(jobName, cloudbrain.CodeMountPath+"/"), | |||||
ModelPath: storage.GetMinioPath(jobName, cloudbrain.ModelMountPath+"/"), | |||||
BenchmarkPath: storage.GetMinioPath(jobName, cloudbrain.BenchMarkMountPath+"/"), | |||||
Snn4ImageNetPath: storage.GetMinioPath(jobName, cloudbrain.Snn4imagenetMountPath+"/"), | |||||
BrainScorePath: storage.GetMinioPath(jobName, cloudbrain.BrainScoreMountPath+"/"), | |||||
JobType: jobType, | |||||
Description: getDescription(option), | |||||
BranchName: option.BranchName, | |||||
BootFile: option.File, | |||||
Params: "{\"parameter\":[]}", | |||||
CommitID: commitID, | |||||
BenchmarkTypeID: 0, | |||||
BenchmarkChildTypeID: 0, | |||||
ResultPath: storage.GetMinioPath(jobName, cloudbrain.ResultPath+"/"), | |||||
Spec: spec, | |||||
} | |||||
jobId, err := cloudbrain.GenerateTask(req) | |||||
if err != nil { | |||||
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(err.Error())) | |||||
return | |||||
} | |||||
ctx.JSON(http.StatusOK, models.BaseMessageApi{ | |||||
Code: 0, | |||||
Message: jobId, | |||||
}) | |||||
} | |||||
func getCodePath(jobName string) string { | |||||
return setting.JobPath + jobName + cloudbrain.CodeMountPath | |||||
} | |||||
func getDescription(option api.CreateFileNotebookJobOption) string { | |||||
return option.OwnerName + "/" + option.ProjectName + "/" + option.File | |||||
} | |||||
func modelartsFileNoteBookCreate(ctx *context.Context, option api.CreateFileNotebookJobOption, repo *models.Repository) { | |||||
displayJobName := cloudbrainService.GetDisplayJobName(ctx.User.Name) | |||||
jobName := util.ConvertDisplayJobNameToJobName(displayJobName) | |||||
lock := redis_lock.NewDistributeLock(redis_key.CloudbrainBindingJobNameKey(fmt.Sprint(repo.ID), string(models.JobTypeDebug), displayJobName)) | |||||
isOk, err := lock.Lock(models.CloudbrainKeyDuration) | |||||
if !isOk { | |||||
log.Error("lock processed failed:%v", err, ctx.Data["MsgID"]) | |||||
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.cloudbrain_samejob_err"))) | |||||
return | |||||
} | |||||
defer lock.UnLock() | |||||
count, err := GetNotFinalStatusTaskCount(ctx.User.ID, models.TypeCloudBrainTwo, string(models.JobTypeDebug)) | |||||
if err != nil { | |||||
log.Error("GetCloudbrainNotebookCountByUserID failed:%v", err, ctx.Data["MsgID"]) | |||||
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi("system error.")) | |||||
return | |||||
} else { | |||||
if count >= 1 { | |||||
log.Error("the user already has running or waiting task", ctx.Data["MsgID"]) | |||||
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.cloudbrain.morethanonejob"))) | |||||
return | |||||
} | |||||
} | |||||
tasks, err := models.GetCloudbrainsByDisplayJobName(repo.ID, string(models.JobTypeDebug), displayJobName) | |||||
if err == nil { | |||||
if len(tasks) != 0 { | |||||
log.Error("the job name did already exist", ctx.Data["MsgID"]) | |||||
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.cloudbrain_samejob_err"))) | |||||
return | |||||
} | |||||
} else { | |||||
if !models.IsErrJobNotExist(err) { | |||||
log.Error("system error, %v", err, ctx.Data["MsgID"]) | |||||
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi("system error.")) | |||||
return | |||||
} | |||||
} | |||||
repoPath := models.RepoPath(repo.OwnerName, repo.Name) | |||||
gitRepo, err := git.OpenRepository(repoPath) | |||||
if err != nil { | |||||
ctx.Error(500, "RepoRef Invalid repo "+repoPath, err.Error()) | |||||
return | |||||
} | |||||
// We opened it, we should close it | |||||
defer func() { | |||||
// If it's been set to nil then assume someone else has closed it. | |||||
if ctx.Repo.GitRepo != nil { | |||||
ctx.Repo.GitRepo.Close() | |||||
} | |||||
}() | |||||
ctx.Repo = &context.Repository{ | |||||
Repository: repo, | |||||
GitRepo: gitRepo, | |||||
} | |||||
fileExist, err := ctx.Repo.FileExists(option.File, option.BranchName) | |||||
if err != nil || !fileExist { | |||||
log.Error("Get file error:", err, ctx.Data["MsgID"]) | |||||
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.notebook_file_not_exist"))) | |||||
return | |||||
} | |||||
err = downloadCode(repo, getCodePath(jobName), option.BranchName) | |||||
if err != nil { | |||||
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("cloudbrain.load_code_failed"))) | |||||
return | |||||
} | |||||
var aiCenterCode = models.AICenterOfCloudBrainTwo | |||||
if setting.ModelartsCD.Enabled { | |||||
aiCenterCode = models.AICenterOfChengdu | |||||
} | |||||
spec, err := resource.GetAndCheckSpec(ctx.User.ID, setting.FileNoteBook.SpecIdNPU, models.FindSpecsOptions{ | |||||
JobType: models.JobTypeDebug, | |||||
ComputeResource: models.NPU, | |||||
Cluster: models.OpenICluster, | |||||
AiCenterCode: aiCenterCode}) | |||||
if err != nil || spec == nil { | |||||
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("cloudbrain.wrong_specification"))) | |||||
return | |||||
} | |||||
if !account.IsPointBalanceEnough(ctx.User.ID, spec.UnitPrice) { | |||||
log.Error("point balance is not enough,userId=%d specId=%d ", ctx.User.ID, spec.ID) | |||||
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("points.insufficient_points_balance"))) | |||||
return | |||||
} | |||||
var jobId string | |||||
if setting.ModelartsCD.Enabled { | |||||
jobId, err = modelarts_cd.GenerateNotebook(ctx, displayJobName, jobName, "", getDescription(option), setting.FileNoteBook.ImageIdNPU, spec, option.File) | |||||
} else { | |||||
jobId, err = modelarts.GenerateNotebook2(ctx, displayJobName, jobName, "", getDescription(option), setting.FileNoteBook.ImageIdNPU, spec, option.File) | |||||
} | |||||
if err != nil { | |||||
log.Error("GenerateNotebook2 failed, %v", err, ctx.Data["MsgID"]) | |||||
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(err.Error())) | |||||
return | |||||
} | |||||
ctx.JSON(http.StatusOK, models.BaseMessageApi{ | |||||
Code: 0, | |||||
Message: jobId, | |||||
}) | |||||
} | |||||
func uploadCodeFile(repo *models.Repository, codePath string, branchName string, filePath string, jobName string) string { | |||||
err := downloadCode(repo, codePath, branchName) | |||||
if err != nil { | |||||
return "cloudbrain.load_code_failed" | |||||
} | |||||
err = uploadOneFileToMinio(codePath, filePath, jobName, cloudbrain.CodeMountPath+"/") | |||||
if err != nil { | |||||
return "cloudbrain.load_code_failed" | |||||
} | |||||
go os.RemoveAll(codePath) | |||||
return "" | |||||
} |
@@ -810,6 +810,18 @@ func uploadCodeToMinio(codePath, jobName, parentDir string) error { | |||||
return nil | return nil | ||||
} | } | ||||
func uploadOneFileToMinio(codePath, filePath, jobName, parentDir string) error { | |||||
destObject := setting.CBCodePathPrefix + jobName + parentDir + path.Base(filePath) | |||||
sourceFile := codePath + filePath | |||||
err := storage.Attachments.UploadObject(destObject, sourceFile) | |||||
if err != nil { | |||||
log.Error("UploadObject(%s) failed: %s", filePath, err.Error()) | |||||
return err | |||||
} | |||||
return nil | |||||
} | |||||
func readDir(dirname string) ([]os.FileInfo, error) { | func readDir(dirname string) ([]os.FileInfo, error) { | ||||
f, err := os.Open(dirname) | f, err := os.Open(dirname) | ||||
if err != nil { | if err != nil { | ||||
@@ -1,27 +1,31 @@ | |||||
package cloudbrain | package cloudbrain | ||||
import ( | import ( | ||||
"regexp" | |||||
"strconv" | |||||
"strings" | |||||
"time" | |||||
"code.gitea.io/gitea/modules/context" | "code.gitea.io/gitea/modules/context" | ||||
"code.gitea.io/gitea/modules/setting" | "code.gitea.io/gitea/modules/setting" | ||||
"strings" | |||||
) | ) | ||||
func GetAiCenterShow(aiCenter string,ctx *context.Context) string{ | |||||
func GetAiCenterShow(aiCenter string, ctx *context.Context) string { | |||||
aiCenterInfo := strings.Split(aiCenter, "+") | aiCenterInfo := strings.Split(aiCenter, "+") | ||||
if len(aiCenterInfo) == 2{ | |||||
if setting.C2NetMapInfo!=nil { | |||||
if info,ok:=setting.C2NetMapInfo[aiCenterInfo[0]];ok { | |||||
if len(aiCenterInfo) == 2 { | |||||
if setting.C2NetMapInfo != nil { | |||||
if info, ok := setting.C2NetMapInfo[aiCenterInfo[0]]; ok { | |||||
if ctx.Language() == "zh-CN" { | if ctx.Language() == "zh-CN" { | ||||
return info.Content | return info.Content | ||||
} else { | } else { | ||||
return info.ContentEN | return info.ContentEN | ||||
} | } | ||||
}else{ | |||||
} else { | |||||
return aiCenterInfo[1] | return aiCenterInfo[1] | ||||
} | } | ||||
}else{ | |||||
} else { | |||||
return aiCenterInfo[1] | return aiCenterInfo[1] | ||||
} | } | ||||
@@ -29,5 +33,26 @@ func GetAiCenterShow(aiCenter string,ctx *context.Context) string{ | |||||
return "" | return "" | ||||
} | |||||
func GetDisplayJobName(username string) string { | |||||
t := time.Now() | |||||
return jobNamePrefixValid(cutString(username, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:] | |||||
} | |||||
func cutString(str string, lens int) string { | |||||
if len(str) < lens { | |||||
return str | |||||
} | |||||
return str[:lens] | |||||
} | |||||
func jobNamePrefixValid(s string) string { | |||||
lowStr := strings.ToLower(s) | |||||
re := regexp.MustCompile(`[^a-z0-9_\\-]+`) | |||||
removeSpecial := re.ReplaceAllString(lowStr, "") | |||||
re = regexp.MustCompile(`^[_\\-]+`) | |||||
return re.ReplaceAllString(removeSpecial, "") | |||||
} | } |