@@ -31,8 +31,8 @@ const (
tplModelManageIndex = "repo/modelmanage/index"
tplModelManageDownload = "repo/modelmanage/download"
tplModelInfo = "repo/modelmanage/showinfo"
tplCreateLocalModelInfo = "repo/modelmanage/create_local_1 "
tplCreateLocalForUploadModelInfo = "repo/modelmanage/create_local_2 "
tplCreateLocalModelInfo = "repo/modelmanage/create_local"
tplCreateLocalForUploadModelInfo = "repo/modelmanage/fileupload "
tplCreateOnlineModelInfo = "repo/modelmanage/create_online"
MODEL_LATEST = 1
@@ -75,14 +75,12 @@ func saveModelByParameters(jobId string, versionName string, name string, versio
}
}
}
cloudType := aiTask.Type
modelSelectedFile := ctx.Query("modelSelectedFile")
//download model zip //train type
if aiTask.ComputeResource == models.NPUResource || aiTask.ComputeResource == models.GCUResource {
cloudType = models.TypeCloudBrainTwo
} else if aiTask.ComputeResource == models.GPUResource {
cloudType = models.TypeCloudBrainOne
}
cloudType := models.TypeCloudBrainTwo
spec, err := resource.GetCloudbrainSpec(aiTask.ID)
if err == nil {
specJson, _ := json.Marshal(spec)
@@ -99,26 +97,27 @@ func saveModelByParameters(jobId string, versionName string, name string, versio
aiTaskJson, _ := json.Marshal(aiTask)
isPrivate := ctx.QueryBool("isPrivate")
model := &models.AiModelManage{
ID: id,
Version: version,
VersionCount: len(aimodels) + 1,
Label: label,
Name: name,
Description: description,
New: MODEL_LATEST,
Type: cloudType,
Path: modelPath,
Size: modelSize,
AttachmentId: aiTask.Uuid,
RepoId: aiTask.RepoID,
UserId: ctx.User.ID,
CodeBranch: aiTask.BranchName,
CodeCommitID: aiTask.CommitID,
Engine: int64(engine),
TrainTaskInfo: string(aiTaskJson),
Accuracy: string(accuracyJson),
Status: STATUS_COPY_MODEL,
IsPrivate: isPrivate,
ID: id,
Version: version,
VersionCount: len(aimodels) + 1,
Label: label,
Name: name,
Description: description,
New: MODEL_LATEST,
Type: cloudType,
Path: modelPath,
Size: modelSize,
AttachmentId: aiTask.Uuid,
RepoId: aiTask.RepoID,
UserId: ctx.User.ID,
CodeBranch: aiTask.BranchName,
CodeCommitID: aiTask.CommitID,
Engine: int64(engine),
TrainTaskInfo: string(aiTaskJson),
Accuracy: string(accuracyJson),
Status: STATUS_COPY_MODEL,
IsPrivate: isPrivate,
ComputeResource: aiTask.ComputeResource,
}
err = models.SaveModelToDb(model)
@@ -145,7 +144,9 @@ func saveModelByParameters(jobId string, versionName string, name string, versio
go asyncToCopyModel(aiTask, id, modelSelectedFile)
log.Info("save model end.")
notification.NotifyOtherTask(ctx.User, ctx.Repo.Repository, id, name, models.ActionCreateNewModelTask)
if !model.IsPrivate {
notification.NotifyOtherTask(ctx.User, ctx.Repo.Repository, id, name, models.ActionCreateNewModelTask)
}
return id, nil
}
@@ -157,6 +158,7 @@ func asyncToCopyModel(aiTask *models.Cloudbrain, id string, modelSelectedFile st
log.Info("download model from CloudBrainTwo faild." + err.Error())
} else {
updateStatus(id, modelSize, STATUS_FINISHED, modelPath, "")
insertModelFile(id)
}
} else if aiTask.ComputeResource == models.GPUResource {
@@ -166,7 +168,24 @@ func asyncToCopyModel(aiTask *models.Cloudbrain, id string, modelSelectedFile st
log.Info("download model from CloudBrainOne faild." + err.Error())
} else {
updateStatus(id, modelSize, STATUS_FINISHED, modelPath, "")
insertModelFile(id)
}
}
}
func insertModelFile(id string) {
model, _ := models.QueryModelById(id)
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=" + id)
}
for _, file := range files {
modelFile := &models.AiModelFile{
ModelID: id,
Name: file.FileName,
Size: file.Size,
}
models.SaveModelFile(modelFile)
}
}
@@ -229,13 +248,23 @@ func SaveLocalModel(ctx *context.Context) {
engine := ctx.QueryInt("engine")
taskType := ctx.QueryInt("type")
isPrivate := ctx.QueryBool("isPrivate")
if ctx.Repo.Repository.IsPrivate {
if !isPrivate {
re["msg"] = "Private repo cannot create public model."
ctx.JSON(200, re)
return
}
}
modelActualPath := ""
computeResource := ""
if taskType == models.TypeCloudBrainOne {
destKeyNamePrefix := Model_prefix + models.AttachmentRelativePath(id) + "/"
modelActualPath = setting.Attachment.Minio.Bucket + "/" + destKeyNamePrefix
computeResource = models.GPUResource
} else if taskType == models.TypeCloudBrainTwo {
destKeyNamePrefix := Model_prefix + models.AttachmentRelativePath(id) + "/"
modelActualPath = setting.Bucket + "/" + destKeyNamePrefix
computeResource = models.NPUResource
} else {
re["msg"] = "type is error."
ctx.JSON(200, re)
@@ -257,25 +286,26 @@ func SaveLocalModel(ctx *context.Context) {
}
}
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,
IsPrivate: isPrivate,
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,
IsPrivate: isPrivate,
ComputeResource: computeResource,
}
err := models.SaveModelToDb(model)
@@ -302,7 +332,9 @@ func SaveLocalModel(ctx *context.Context) {
models.UpdateRepositoryUnits(ctx.Repo.Repository, units, deleteUnitTypes)
log.Info("save model end.")
notification.NotifyOtherTask(ctx.User, ctx.Repo.Repository, id, name, models.ActionCreateNewModelTask)
if !model.IsPrivate {
notification.NotifyOtherTask(ctx.User, ctx.Repo.Repository, id, name, models.ActionCreateNewModelTask)
}
re["code"] = "0"
re["id"] = id
ctx.JSON(200, re)
@@ -316,27 +348,33 @@ func getSize(files []storage.FileInfo) int64 {
return size
}
func UpdateModelSize(modeluuid string) {
func UpdateModelSize(modeluuid string, objectName string ) {
model, err := models.QueryModelById(modeluuid)
if err == nil {
var size int64
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)
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)
}
} 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)
modelFileName := objectName
index := strings.LastIndex(objectName, "/")
if index > 0 {
modelFileName = objectName[index+1:]
}
log.Info("modelFileName=" + modelFileName)
for _, file := range files {
log.Info("fileName=" + file.FileName)
if file.FileName == modelFileName {
modelFile := &models.AiModelFile{
ModelID: modeluuid,
Name: file.FileName,
Size: file.Size,
}
models.SaveModelFile(modelFile)
}
size = getSize(files)
models.ModifyModelSize(modeluuid, size)
}
}
if model.Size == 0 && size > 0 {
@@ -365,6 +403,14 @@ func SaveModel(ctx *context.Context) {
re := map[string]string{
"code": "-1",
}
isPrivate := ctx.QueryBool("isPrivate")
if ctx.Repo.Repository.IsPrivate {
if !isPrivate {
re["msg"] = "Private repo cannot create public model."
ctx.JSON(200, re)
return
}
}
if JobId == "" || VersionName == "" {
re["msg"] = "JobId or VersionName is null."
ctx.JSON(200, re)
@@ -427,10 +473,10 @@ func downloadModelFromCloudBrainTwo(modelUUID string, jobName string, parentDir
}
func downloadModelFromCloudBrainOne(modelUUID string, jobName string, parentDir string, trainUrl string, modelSelectedFile string) (string, int64, error) {
modelActualPath := storage.GetMinioPath(jobName, "/model/")
log.Info("modelActualPath=" + modelActualPath)
modelSrcPrefix := setting.CBCodePathPrefix + jobName + "/model/"
destKeyNamePrefix := Model_prefix + models.AttachmentRelativePath(modelUUID) + "/"
modelSrcPrefix := setting.CBCodePathPrefix + jobName + "/model/"
//destKeyNamePrefix := Model_prefix + models.AttachmentRelativePath(modelUUID) + "/"
bucketName := setting.Attachment.Minio.Bucket
log.Info("destKeyNamePrefix=" + destKeyNamePrefix + " modelSrcPrefix=" + modelSrcPrefix + " bucket=" + bucketName)
filterFiles := strings.Split(modelSelectedFile, ";")
@@ -442,13 +488,25 @@ func downloadModelFromCloudBrainOne(modelUUID string, jobName string, parentDir
if float64(totalSize) > setting.MaxModelSize*MODEL_MAX_SIZE {
return "", 0, errors.New("Cannot create model, as model is exceed " + fmt.Sprint(setting.MaxModelSize) + "G.")
}
size, err := storage.MinioCopyFiles(bucketName, modelSrcPrefix, destKeyNamePrefix, filterFiles)
if err == nil {
dataActualPath := bucketName + "/" + destKeyNamePrefix
return dataActualPath, size, nil
} else {
return "", 0, nil
for i, modelFile := range Files {
reader, err := storage.Attachments.DownloadAFile(bucketName, modelFile)
if err == nil {
defer reader.Close()
log.Info("upload to bucket=" + setting.Bucket + " objectKey=" + destKeyNamePrefix + filterFiles[i])
obsErr := storage.PutReaderToObs(setting.Bucket, destKeyNamePrefix+filterFiles[i], reader)
if obsErr != nil {
log.Info("upload to obs failed.err=" + obsErr.Error())
return "", 0, nil
}
}
}
//size, err := storage.MinioCopyFiles(bucketName, modelSrcPrefix, destKeyNamePrefix, filterFiles)
dataActualPath := setting.Bucket + "/" + destKeyNamePrefix
//dataActualPath := bucketName + "/" + destKeyNamePrefix
return dataActualPath, totalSize, nil
}
func DeleteModelFile(ctx *context.Context) {
log.Info("delete model start.")
@@ -458,47 +516,32 @@ func DeleteModelFile(ctx *context.Context) {
if err == nil {
var totalSize int64
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)
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",
}
}
} 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)
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)
modelFile := &models.AiModelFile{
Name: fileName,
ModelID: id,
}
models.DeleteModelFile(modelFile)
}
}
}
if (model.Size - totalSize) <= 0 {
go repository.ResetRepoModelNum(model.RepoId)
@@ -534,24 +577,12 @@ func deleteModelByID(ctx *context.Context, id string) error {
}
if err == nil {
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
}
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
}
}
@@ -908,20 +939,37 @@ func QueryModelById(ctx *context.Context) {
func ShowSingleModel(ctx *context.Context) {
name := ctx.Query("name")
log.Info("Show single ModelInfo start.name=" + name)
models := models.QueryModelByName(name, ctx.Repo.Repository.ID)
userIds := make([]int64, len(models))
for i, model := range models {
modelArrays := models.QueryModelByName(name, ctx.Repo.Repository.ID)
modelResult := make([]*models.AiModelManage, 0)
isCanReadPrivateModel := isQueryPrivateModel(ctx)
userIds := make([]int64, len(modelArrays))
for i, model := range modelArrays {
model.IsCanOper = isOperModifyOrDelete(ctx, model.UserId)
model.IsCanDownload = isCanDownload(ctx, model)
model.IsCanDelete = isCanDelete(ctx, model.UserId)
model.RepoName = ctx.Repo.Repository.Name
model.RepoOwnerName = ctx.Repo.Repository.OwnerName
model.RepoDisplayName = ctx.Repo.Repository.DisplayName()
userIds[i] = model.UserId
if ctx.User != nil {
re := models.QueryModelCollectByUserId(model.ID, ctx.User.ID)
if re != nil && len(re) > 0 {
model.IsCollected = true
}
}
if model.IsPrivate {
if !isCanReadPrivateModel {
continue
}
}
modelResult = append(modelResult, model)
}
userNameMap := queryUserName(userIds)
for _, model := range models {
for _, model := range modelRe sult {
removeIpInfo(model)
value := userNameMap[model.UserId]
if value != nil {
@@ -929,7 +977,7 @@ func ShowSingleModel(ctx *context.Context) {
model.UserRelAvatarLink = value.RelAvatarLink()
}
}
ctx.JSON(http.StatusOK, models)
ctx.JSON(http.StatusOK, modelRe sult )
}
func removeIpInfo(model *models.AiModelManage) {
@@ -1002,6 +1050,7 @@ func SetModelCount(ctx *context.Context) {
New: MODEL_LATEST,
IsOnlyThisRepo: true,
Status: -1,
FrameFilter: -1,
IsQueryPrivate: isQueryPrivate,
})
ctx.Data["MODEL_COUNT"] = count
@@ -1140,6 +1189,7 @@ func ShowModelPageInfo(ctx *context.Context) {
IsOnlyThisRepo: true,
Status: -1,
IsQueryPrivate: isQueryPrivate,
FrameFilter: -1,
})
if err != nil {
ctx.ServerError("Cloudbrain", err)
@@ -1171,16 +1221,6 @@ func ShowModelPageInfo(ctx *context.Context) {
ctx.JSON(http.StatusOK, mapInterface)
}
func ModifyModel(id string, description string) error {
err := models.ModifyModelDescription(id, description)
if err == nil {
log.Info("modify success.")
} else {
log.Info("Failed to modify.id=" + id + " desc=" + description + " error:" + err.Error())
}
return err
}
func ModifyModelPrivate(ctx *context.Context) {
id := ctx.Query("id")
isPrivate := ctx.QueryBool("isPrivate")
@@ -1230,34 +1270,34 @@ func ModifyModelInfo(ctx *context.Context) {
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")
isPrivate := ctx.QueryBool("isPrivate")
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 {
name := ctx.Query("name")
label := ctx.Query("label")
description := ctx.Query("description")
engine := ctx.QueryInt("engine")
isPrivate := ctx.QueryBool("isPrivate")
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, isPrivate)
if task.Name != name {
aimodels = models.QueryModelByName(task.Name, task.RepoId)
if aimodels != nil && len(aimodels) > 0 {
for _, model := range aimodels {
models.ModifyLocalModel(model.ID, name, model.Label, model.Description, int(model.Engine), model.IsPrivate)
}
}
err = models.ModifyLocalModel(id, name, label, description, engine, isPrivate)
} else {
label := ctx.Query("label")
description := ctx.Query("description")
engine := task.Engine
name := task.Name
err = models.ModifyLocalModel(id, name, label, description, int(engine), task.IsPrivate)
}
if err != nil {
@@ -1288,11 +1328,12 @@ func QueryModelListForPredict(ctx *context.Context) {
PageSize: pageSize,
},
RepoID: repoId,
Type: ctx.QueryInt("type") ,
Type: -1 ,
New: -1,
Status: 0,
IsOnlyThisRepo: true,
IsQueryPrivate: isQueryPrivate,
FrameFilter: -1,
})
if err != nil {
ctx.ServerError("Cloudbrain", err)
@@ -1349,26 +1390,27 @@ func QueryOneLevelModelFile(ctx *context.Context) {
model, err := models.QueryModelById(id)
if err != nil {
log.Error("no such model!", err.Error())
ctx.ServerError("no such model:", err )
ctx.JSON(http.StatusOK, nil )
return
}
ctx.JSON(http.StatusOK, queryOneLevelModelFile(model, parentDir))
}
func queryOneLevelModelFile(model *models.AiModelManage, parentDir string) []storage.FileInfo {
fileinfos := make([]storage.FileInfo, 0)
if model.Type == models.TypeCloudBrainTwo {
log.Info("TypeCloudBrainTwo list model file.")
prefix := model.Path[len(setting.Bucket)+1:]
fileinfos, _ := storage.GetOneLevelAllObjectUnderDir(setting.Bucket, prefix, parentDir)
if fileinfos == nil {
fileinfos = make([]storage.FileInfo, 0)
}
ctx.JSON(http.StatusOK, fileinfos)
prefix := model.Path[len(setting.Bucket)+1:] + parentDir
fileinfos, _ = storage.GetOneLevelAllObjectUnderDir(setting.Bucket, prefix, "")
} else if model.Type == models.TypeCloudBrainOne {
log.Info("TypeCloudBrainOne list model file.")
prefix := model.Path[len(setting.Attachment.Minio.Bucket)+1:]
fileinfos, _ := storage.GetOneLevelAllObjectUnderDirMinio(setting.Attachment.Minio.Bucket, prefix, parentDir)
if fileinfos == nil {
fileinfos = make([]storage.FileInfo, 0)
}
ctx.JSON(http.StatusOK, fileinfos)
prefix := model.Path[len(setting.Attachment.Minio.Bucket)+1:] + parentDir
fileinfos, _ = storage.GetOneLevelAllObjectUnderDirMinio(setting.Attachment.Minio.Bucket, prefix, "")
}
if fileinfos == nil {
fileinfos = make([]storage.FileInfo, 0)
}
return fileinfos
}
func CreateLocalModel(ctx *context.Context) {
@@ -1392,3 +1434,60 @@ func CreateOnlineModel(ctx *context.Context) {
ctx.HTML(200, tplCreateOnlineModelInfo)
}
func QueryModelCollectNum(ctx *context.Context) {
id := ctx.Query("id")
record := models.QueryModelCollectNum(id)
ctx.JSON(200, record)
}
func ModelCollect(ctx *context.Context) {
id := ctx.Query("id")
isCollected := ctx.QueryBool("collected")
re := map[string]string{
"code": "-1",
}
task, err := models.QueryModelById(id)
if err != nil || task == nil {
re["msg"] = err.Error()
log.Error("no such model!", err.Error())
ctx.JSON(200, re)
return
}
if ctx.User == nil {
re["msg"] = "user not login."
re["code"] = "401"
ctx.JSON(200, re)
return
}
record := models.QueryModelCollectByUserId(id, ctx.User.ID)
if isCollected {
if record == nil || len(record) == 0 {
log.Info("user collect the model.user id=" + fmt.Sprint(ctx.User.ID) + " model id=" + id)
err := models.SaveModelCollect(&models.AiModelCollect{
ModelID: id,
UserId: ctx.User.ID,
})
if err == nil {
re["code"] = "0"
} else {
re["msg"] = err.Error()
}
}
} else {
if record != nil && len(record) > 0 {
log.Info("user delete collect the model.user id=" + fmt.Sprint(ctx.User.ID) + " model id=" + id)
err := models.DeleteModelCollect(&models.AiModelCollect{
ID: record[0].ID,
})
if err == nil {
re["code"] = "0"
} else {
re["msg"] = err.Error()
}
}
}
num := models.QueryModelCollectNum(id)
models.ModifyModelCollectedNum(id, num)
ctx.JSON(200, re)
}