| @@ -194,32 +194,6 @@ func (Specification) TableName() string { | |||||
| return "resource_specification" | return "resource_specification" | ||||
| } | } | ||||
| func (s *Specification) ToShow() *SpecificationShow { | |||||
| return &SpecificationShow{ | |||||
| ID: s.ID, | |||||
| AccCardsNum: s.AccCardsNum, | |||||
| AccCardType: s.AccCardType, | |||||
| CpuCores: s.CpuCores, | |||||
| MemGiB: s.MemGiB, | |||||
| GPUMemGiB: s.GPUMemGiB, | |||||
| ShareMemGiB: s.ShareMemGiB, | |||||
| ComputeResource: s.ComputeResource, | |||||
| UnitPrice: s.UnitPrice, | |||||
| } | |||||
| } | |||||
| type SpecificationShow struct { | |||||
| ID int64 `json:"id"` | |||||
| AccCardsNum int `json:"acc_cards_num"` | |||||
| AccCardType string `json:"acc_card_type"` | |||||
| CpuCores int `json:"cpu_cores"` | |||||
| MemGiB float32 `json:"mem_gi_b"` | |||||
| GPUMemGiB float32 `json:"gpu_mem_gi_b"` | |||||
| ShareMemGiB float32 `json:"share_mem_gi_b"` | |||||
| ComputeResource string `json:"compute_resource"` | |||||
| UnitPrice int `json:"unit_price"` | |||||
| } | |||||
| func InsertResourceSpecification(r ResourceSpecification) (int64, error) { | func InsertResourceSpecification(r ResourceSpecification) (int64, error) { | ||||
| return x.Insert(&r) | return x.Insert(&r) | ||||
| } | } | ||||
| @@ -0,0 +1,103 @@ | |||||
| package convert | |||||
| import ( | |||||
| "code.gitea.io/gitea/models" | |||||
| api "code.gitea.io/gitea/modules/structs" | |||||
| ) | |||||
| func ToCloudBrain(task *models.Cloudbrain) *api.Cloudbrain { | |||||
| return &api.Cloudbrain{ | |||||
| ID: task.ID, | |||||
| JobID: task.JobID, | |||||
| JobType: task.JobType, | |||||
| Type: task.Type, | |||||
| DisplayJobName: task.DisplayJobName, | |||||
| Status: task.Status, | |||||
| CreatedUnix: int64(task.CreatedUnix), | |||||
| RepoID: task.RepoID, | |||||
| Duration: task.Duration, | |||||
| TrainJobDuration: task.TrainJobDuration, | |||||
| ImageID: task.ImageID, | |||||
| Image: task.Image, | |||||
| Uuid: task.Uuid, | |||||
| DatasetName: task.DatasetName, | |||||
| ComputeResource: task.ComputeResource, | |||||
| AiCenter: task.AiCenter, | |||||
| BranchName: task.BranchName, | |||||
| Parameters: task.Parameters, | |||||
| BootFile: task.BootFile, | |||||
| Description: task.Description, | |||||
| ModelName: task.ModelName, | |||||
| ModelVersion: task.ModelVersion, | |||||
| CkptName: task.CkptName, | |||||
| StartTime: int64(task.StartTime), | |||||
| EndTime: int64(task.EndTime), | |||||
| Spec: ToSpecification(task.Spec), | |||||
| } | |||||
| } | |||||
| func ToAttachment(attachment *models.Attachment) *api.AttachmentShow { | |||||
| return &api.AttachmentShow{ | |||||
| ID: attachment.ID, | |||||
| UUID: attachment.UUID, | |||||
| DatasetID: attachment.DatasetID, | |||||
| ReleaseID: attachment.ReleaseID, | |||||
| UploaderID: attachment.UploaderID, | |||||
| CommentID: attachment.CommentID, | |||||
| Name: attachment.Name, | |||||
| Description: attachment.Description, | |||||
| DownloadCount: attachment.DownloadCount, | |||||
| UseNumber: attachment.UseNumber, | |||||
| Size: attachment.Size, | |||||
| IsPrivate: attachment.IsPrivate, | |||||
| DecompressState: attachment.DecompressState, | |||||
| Type: attachment.Type, | |||||
| CreatedUnix: int64(attachment.CreatedUnix), | |||||
| } | |||||
| } | |||||
| func ToDataset(dataset *models.Dataset) *api.Dataset { | |||||
| var convertAttachments []*api.AttachmentShow | |||||
| for _, attachment := range dataset.Attachments { | |||||
| convertAttachments = append(convertAttachments, ToAttachment(attachment)) | |||||
| } | |||||
| return &api.Dataset{ | |||||
| ID: dataset.ID, | |||||
| Title: dataset.Title, | |||||
| Status: dataset.Status, | |||||
| Category: dataset.Category, | |||||
| Description: dataset.Description, | |||||
| DownloadTimes: dataset.DownloadTimes, | |||||
| UseCount: dataset.UseCount, | |||||
| NumStars: dataset.NumStars, | |||||
| Recommend: dataset.Recommend, | |||||
| License: dataset.License, | |||||
| Task: dataset.Task, | |||||
| ReleaseID: dataset.ReleaseID, | |||||
| UserID: dataset.UserID, | |||||
| RepoID: dataset.RepoID, | |||||
| Repo: &api.RepositoryShow{ | |||||
| OwnerName: dataset.Repo.OwnerName, | |||||
| Name: dataset.Repo.Name, | |||||
| }, | |||||
| CreatedUnix: int64(dataset.CreatedUnix), | |||||
| UpdatedUnix: int64(dataset.UpdatedUnix), | |||||
| Attachments: convertAttachments, | |||||
| } | |||||
| } | |||||
| func ToSpecification(s *models.Specification) *api.SpecificationShow { | |||||
| return &api.SpecificationShow{ | |||||
| ID: s.ID, | |||||
| AccCardsNum: s.AccCardsNum, | |||||
| AccCardType: s.AccCardType, | |||||
| CpuCores: s.CpuCores, | |||||
| MemGiB: s.MemGiB, | |||||
| GPUMemGiB: s.GPUMemGiB, | |||||
| ShareMemGiB: s.ShareMemGiB, | |||||
| ComputeResource: s.ComputeResource, | |||||
| UnitPrice: s.UnitPrice, | |||||
| } | |||||
| } | |||||
| @@ -6,8 +6,6 @@ package structs // import "code.gitea.io/gitea/modules/structs" | |||||
| import ( | import ( | ||||
| "time" | "time" | ||||
| "code.gitea.io/gitea/modules/timeutil" | |||||
| ) | ) | ||||
| // Attachment a generic attachment | // Attachment a generic attachment | ||||
| @@ -31,23 +29,23 @@ type EditAttachmentOptions struct { | |||||
| } | } | ||||
| type Dataset struct { | type Dataset struct { | ||||
| ID int64 `json:"id"` | |||||
| Title string `json:"title"` | |||||
| Status int32 `json:"status"` | |||||
| Category string `json:"category"` | |||||
| Description string `json:"description"` | |||||
| DownloadTimes int64 `json:"downloadTimes"` | |||||
| UseCount int64 `json:"useCount"` | |||||
| NumStars int `json:"numStars"` | |||||
| Recommend bool `json:"recommend"` | |||||
| License string `json:"license"` | |||||
| Task string `json:"task"` | |||||
| ReleaseID int64 `json:"releaseId"` | |||||
| UserID int64 `json:"userId"` | |||||
| RepoID int64 `json:"repoId"` | |||||
| Repo *RepositoryShow `json:"repo"` | |||||
| CreatedUnix timeutil.TimeStamp `json:"createdUnix"` | |||||
| UpdatedUnix timeutil.TimeStamp `json:"updatedUnix"` | |||||
| ID int64 `json:"id"` | |||||
| Title string `json:"title"` | |||||
| Status int32 `json:"status"` | |||||
| Category string `json:"category"` | |||||
| Description string `json:"description"` | |||||
| DownloadTimes int64 `json:"downloadTimes"` | |||||
| UseCount int64 `json:"useCount"` | |||||
| NumStars int `json:"numStars"` | |||||
| Recommend bool `json:"recommend"` | |||||
| License string `json:"license"` | |||||
| Task string `json:"task"` | |||||
| ReleaseID int64 `json:"releaseId"` | |||||
| UserID int64 `json:"userId"` | |||||
| RepoID int64 `json:"repoId"` | |||||
| Repo *RepositoryShow `json:"repo"` | |||||
| CreatedUnix int64 `json:"createdUnix"` | |||||
| UpdatedUnix int64 `json:"updatedUnix"` | |||||
| Attachments []*AttachmentShow `json:"attachments"` | Attachments []*AttachmentShow `json:"attachments"` | ||||
| } | } | ||||
| @@ -58,19 +56,19 @@ type RepositoryShow struct { | |||||
| } | } | ||||
| type AttachmentShow struct { | type AttachmentShow struct { | ||||
| ID int64 `json:"id"` | |||||
| UUID string `json:"uuid"` | |||||
| DatasetID int64 `json:"datasetId"` | |||||
| ReleaseID int64 `json:"releaseId"` | |||||
| UploaderID int64 `json:"uploaderId"` | |||||
| CommentID int64 `json:"commentId"` | |||||
| Name string `json:"name"` | |||||
| Description string `json:"description"` | |||||
| DownloadCount int64 `json:"downloadCount"` | |||||
| UseNumber int64 `json:"useNumber"` | |||||
| Size int64 `json:"size"` | |||||
| IsPrivate bool `json:"isPrivate"` | |||||
| DecompressState int32 `json:"decompressState"` | |||||
| Type int `json:"type"` | |||||
| CreatedUnix timeutil.TimeStamp `json:"createdUnix"` | |||||
| ID int64 `json:"id"` | |||||
| UUID string `json:"uuid"` | |||||
| DatasetID int64 `json:"datasetId"` | |||||
| ReleaseID int64 `json:"releaseId"` | |||||
| UploaderID int64 `json:"uploaderId"` | |||||
| CommentID int64 `json:"commentId"` | |||||
| Name string `json:"name"` | |||||
| Description string `json:"description"` | |||||
| DownloadCount int64 `json:"downloadCount"` | |||||
| UseNumber int64 `json:"useNumber"` | |||||
| Size int64 `json:"size"` | |||||
| IsPrivate bool `json:"isPrivate"` | |||||
| DecompressState int32 `json:"decompressState"` | |||||
| Type int `json:"type"` | |||||
| CreatedUnix int64 `json:"createdUnix"` | |||||
| } | } | ||||
| @@ -1,10 +1,5 @@ | |||||
| package structs | package structs | ||||
| import ( | |||||
| "code.gitea.io/gitea/models" | |||||
| "code.gitea.io/gitea/modules/timeutil" | |||||
| ) | |||||
| type CreateGrampusTrainJobOption struct { | type CreateGrampusTrainJobOption struct { | ||||
| DisplayJobName string `json:"display_job_name" binding:"Required"` | DisplayJobName string `json:"display_job_name" binding:"Required"` | ||||
| JobName string `json:"job_name" binding:"Required" ` | JobName string `json:"job_name" binding:"Required" ` | ||||
| @@ -47,36 +42,43 @@ type CreateTrainJobOption struct { | |||||
| } | } | ||||
| type Cloudbrain struct { | type Cloudbrain struct { | ||||
| ID int64 `json:"id"` | |||||
| JobID string `json:"job_id"` | |||||
| JobType string `json:"job_type"` | |||||
| Type int `json:"type"` | |||||
| DisplayJobName string `json:"display_job_name"` | |||||
| Status string `json:"status"` | |||||
| CreatedUnix timeutil.TimeStamp `json:"created_unix"` | |||||
| RepoID int64 `json:"repo_id"` | |||||
| Duration int64 `json:"duration"` //运行时长 单位秒 | |||||
| TrainJobDuration string `json:"train_job_duration"` | |||||
| ImageID string `json:"image_id"` //grampus image_id | |||||
| Image string `json:"image"` | |||||
| Uuid string `json:"uuid"` //数据集id | |||||
| DatasetName string `json:"dataset_name"` | |||||
| ComputeResource string `json:"compute_resource"` //计算资源,例如npu | |||||
| AiCenter string `json:"ai_center"` //grampus ai center: center_id+center_name | |||||
| BranchName string `json:"branch_name"` //分支名称 | |||||
| Parameters string `json:"parameters"` //传给modelarts的param参数 | |||||
| BootFile string `json:"boot_file"` //启动文件 | |||||
| Description string `json:"description"` //描述 | |||||
| ModelName string `json:"model_name"` //模型名称 | |||||
| ModelVersion string `json:"model_version"` //模型版本 | |||||
| CkptName string `json:"ckpt_name"` //权重文件名称 | |||||
| ID int64 `json:"id"` | |||||
| JobID string `json:"job_id"` | |||||
| JobType string `json:"job_type"` | |||||
| Type int `json:"type"` | |||||
| DisplayJobName string `json:"display_job_name"` | |||||
| Status string `json:"status"` | |||||
| CreatedUnix int64 `json:"created_unix"` | |||||
| RepoID int64 `json:"repo_id"` | |||||
| Duration int64 `json:"duration"` //运行时长 单位秒 | |||||
| TrainJobDuration string `json:"train_job_duration"` | |||||
| ImageID string `json:"image_id"` //grampus image_id | |||||
| Image string `json:"image"` | |||||
| Uuid string `json:"uuid"` //数据集id | |||||
| DatasetName string `json:"dataset_name"` | |||||
| ComputeResource string `json:"compute_resource"` //计算资源,例如npu | |||||
| AiCenter string `json:"ai_center"` //grampus ai center: center_id+center_name | |||||
| BranchName string `json:"branch_name"` //分支名称 | |||||
| Parameters string `json:"parameters"` //传给modelarts的param参数 | |||||
| BootFile string `json:"boot_file"` //启动文件 | |||||
| Description string `json:"description"` //描述 | |||||
| ModelName string `json:"model_name"` //模型名称 | |||||
| ModelVersion string `json:"model_version"` //模型版本 | |||||
| CkptName string `json:"ckpt_name"` //权重文件名称 | |||||
| StartTime int64 `json:"start_time"` | |||||
| EndTime int64 `json:"end_time"` | |||||
| VersionCount int `json:"-"` //任务的当前版本数量,不包括删除的 | |||||
| IsLatestVersion string `json:"-"` //是否是最新版本,1是,0否 | |||||
| CommitID string `json:"-"` //提交的仓库代码id | |||||
| PreVersionName string `json:"-"` //父版本名称 | |||||
| StartTime timeutil.TimeStamp `json:"start_time"` | |||||
| EndTime timeutil.TimeStamp `json:"end_time"` | |||||
| Spec *SpecificationShow `json:"spec"` | |||||
| } | |||||
| Spec *models.Specification `json:"spec"` | |||||
| type SpecificationShow struct { | |||||
| ID int64 `json:"id"` | |||||
| AccCardsNum int `json:"acc_cards_num"` | |||||
| AccCardType string `json:"acc_card_type"` | |||||
| CpuCores int `json:"cpu_cores"` | |||||
| MemGiB float32 `json:"mem_gi_b"` | |||||
| GPUMemGiB float32 `json:"gpu_mem_gi_b"` | |||||
| ShareMemGiB float32 `json:"share_mem_gi_b"` | |||||
| ComputeResource string `json:"compute_resource"` | |||||
| UnitPrice int `json:"unit_price"` | |||||
| } | } | ||||
| @@ -242,6 +242,15 @@ func reqRepoWriter(unitTypes ...models.UnitType) macaron.Handler { | |||||
| } | } | ||||
| } | } | ||||
| func reqWeChat() macaron.Handler { | |||||
| return func(ctx *context.Context) { | |||||
| if setting.WechatAuthSwitch && ctx.User.WechatOpenId == "" { | |||||
| ctx.JSON(http.StatusForbidden, models.BaseErrorMessageApi("settings.no_wechat_bind")) | |||||
| return | |||||
| } | |||||
| } | |||||
| } | |||||
| // reqRepoReader user should have specific read permission or be a repo admin or a site admin | // reqRepoReader user should have specific read permission or be a repo admin or a site admin | ||||
| func reqRepoReader(unitType models.UnitType) macaron.Handler { | func reqRepoReader(unitType models.UnitType) macaron.Handler { | ||||
| return func(ctx *context.Context) { | return func(ctx *context.Context) { | ||||
| @@ -526,6 +535,16 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
| }, reqToken()) | }, reqToken()) | ||||
| m.Group("/attachments", func() { | |||||
| m.Get("/:uuid", repo.GetAttachment) | |||||
| m.Get("/get_chunks", repo.GetSuccessChunks) | |||||
| m.Get("/new_multipart", repo.NewMultipart) | |||||
| m.Get("/get_multipart_url", repo.GetMultipartUploadUrl) | |||||
| m.Post("/complete_multipart", repo.CompleteMultipart) | |||||
| }, reqToken()) | |||||
| // Notifications | // Notifications | ||||
| m.Group("/notifications", func() { | m.Group("/notifications", func() { | ||||
| m.Combo(""). | m.Combo(""). | ||||
| @@ -982,15 +1001,17 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
| }, reqRepoReader(models.UnitTypeModelManage)) | }, reqRepoReader(models.UnitTypeModelManage)) | ||||
| m.Group("/cloudbrain", func() { | m.Group("/cloudbrain", func() { | ||||
| m.Group("/train-job", func() { | m.Group("/train-job", func() { | ||||
| m.Post("/create", bind(api.CreateTrainJobOption{}), repo.CreateCloudBrain) | |||||
| m.Get("/:jobid", reqRepoReader(models.UnitTypeCloudBrain), repo.CloudBrainShow) | |||||
| m.Post("/create", reqRepoWriter(models.UnitTypeCloudBrain), reqWeChat, bind(api.CreateTrainJobOption{}), repo.CreateCloudBrain) | |||||
| }) | }) | ||||
| m.Group("/inference-job", func() { | m.Group("/inference-job", func() { | ||||
| m.Post("/create", bind(api.CreateTrainJobOption{}), repo.CreateCloudBrainInferenceTask) | |||||
| m.Post("/create", reqRepoWriter(models.UnitTypeCloudBrain), reqWeChat, bind(api.CreateTrainJobOption{}), repo.CreateCloudBrainInferenceTask) | |||||
| m.Get("/:jobid", reqRepoReader(models.UnitTypeCloudBrain), repo.CloudBrainShow) | |||||
| }) | }) | ||||
| }, reqRepoReader(models.UnitTypeCloudBrain)) | |||||
| }, reqToken()) | |||||
| m.Group("/modelarts", func() { | m.Group("/modelarts", func() { | ||||
| m.Group("/notebook", func() { | m.Group("/notebook", func() { | ||||
| //m.Get("/:jobid", repo.GetModelArtsNotebook) | //m.Get("/:jobid", repo.GetModelArtsNotebook) | ||||
| @@ -0,0 +1,25 @@ | |||||
| package repo | |||||
| import ( | |||||
| "code.gitea.io/gitea/modules/context" | |||||
| routeRepo "code.gitea.io/gitea/routers/repo" | |||||
| ) | |||||
| func GetSuccessChunks(ctx *context.APIContext) { | |||||
| routeRepo.GetSuccessChunks(ctx.Context) | |||||
| } | |||||
| func NewMultipart(ctx *context.APIContext) { | |||||
| routeRepo.NewMultipart(ctx.Context) | |||||
| } | |||||
| func GetMultipartUploadUrl(ctx *context.APIContext) { | |||||
| routeRepo.GetMultipartUploadUrl(ctx.Context) | |||||
| } | |||||
| func CompleteMultipart(ctx *context.APIContext) { | |||||
| routeRepo.CompleteMultipart(ctx.Context) | |||||
| } | |||||
| func GetAttachment(ctx *context.APIContext) { | |||||
| routeRepo.GetAttachment(ctx.Context) | |||||
| } | |||||
| @@ -16,6 +16,8 @@ import ( | |||||
| "strings" | "strings" | ||||
| "time" | "time" | ||||
| "code.gitea.io/gitea/modules/convert" | |||||
| "code.gitea.io/gitea/services/cloudbrain/cloudbrainTask" | "code.gitea.io/gitea/services/cloudbrain/cloudbrainTask" | ||||
| api "code.gitea.io/gitea/modules/structs" | api "code.gitea.io/gitea/modules/structs" | ||||
| @@ -71,7 +73,7 @@ func CloudBrainShow(ctx *context.APIContext) { | |||||
| task.Image = task.EngineName | task.Image = task.EngineName | ||||
| } | } | ||||
| ctx.JSON(http.StatusOK, models.BaseMessageWithDataApi{Code: 0, Message: "", Data: task}) | |||||
| ctx.JSON(http.StatusOK, models.BaseMessageWithDataApi{Code: 0, Message: "", Data: convert.ToCloudBrain(task)}) | |||||
| } | } | ||||
| @@ -4,6 +4,10 @@ import ( | |||||
| "fmt" | "fmt" | ||||
| "strings" | "strings" | ||||
| "code.gitea.io/gitea/modules/convert" | |||||
| api "code.gitea.io/gitea/modules/structs" | |||||
| "code.gitea.io/gitea/models" | "code.gitea.io/gitea/models" | ||||
| "code.gitea.io/gitea/modules/context" | "code.gitea.io/gitea/modules/context" | ||||
| "code.gitea.io/gitea/modules/log" | "code.gitea.io/gitea/modules/log" | ||||
| @@ -88,15 +92,20 @@ func datasetMultiple(ctx *context.APIContext, opts *models.SearchDatasetOptions) | |||||
| ctx.JSON(200, map[string]interface{}{ | ctx.JSON(200, map[string]interface{}{ | ||||
| "code": 1, | "code": 1, | ||||
| "message": err.Error(), | "message": err.Error(), | ||||
| "data": []*models.Dataset{}, | |||||
| "data": []*api.Dataset{}, | |||||
| "count": 0, | "count": 0, | ||||
| }) | }) | ||||
| return | return | ||||
| } | } | ||||
| var convertDatasets []*api.Dataset | |||||
| for _, dataset := range datasets { | |||||
| convertDatasets = append(convertDatasets, convert.ToDataset(dataset)) | |||||
| } | |||||
| ctx.JSON(200, map[string]interface{}{ | ctx.JSON(200, map[string]interface{}{ | ||||
| "code": 0, | "code": 0, | ||||
| "message": "", | "message": "", | ||||
| "data": datasets, | |||||
| "data": convertDatasets, | |||||
| "count": count, | "count": count, | ||||
| }) | }) | ||||
| } | } | ||||
| @@ -1,20 +1,23 @@ | |||||
| package resource | package resource | ||||
| import ( | import ( | ||||
| "encoding/json" | |||||
| "errors" | |||||
| "fmt" | |||||
| "strconv" | |||||
| "strings" | |||||
| "time" | |||||
| "code.gitea.io/gitea/models" | "code.gitea.io/gitea/models" | ||||
| "code.gitea.io/gitea/modules/cloudbrain" | "code.gitea.io/gitea/modules/cloudbrain" | ||||
| "code.gitea.io/gitea/modules/convert" | |||||
| "code.gitea.io/gitea/modules/grampus" | "code.gitea.io/gitea/modules/grampus" | ||||
| "code.gitea.io/gitea/modules/log" | "code.gitea.io/gitea/modules/log" | ||||
| "code.gitea.io/gitea/modules/modelarts" | "code.gitea.io/gitea/modules/modelarts" | ||||
| "code.gitea.io/gitea/modules/setting" | "code.gitea.io/gitea/modules/setting" | ||||
| api "code.gitea.io/gitea/modules/structs" | |||||
| "code.gitea.io/gitea/routers/response" | "code.gitea.io/gitea/routers/response" | ||||
| "code.gitea.io/gitea/services/admin/operate_log" | "code.gitea.io/gitea/services/admin/operate_log" | ||||
| "encoding/json" | |||||
| "errors" | |||||
| "fmt" | |||||
| "strconv" | |||||
| "strings" | |||||
| "time" | |||||
| ) | ) | ||||
| func AddResourceSpecification(doerId int64, req models.ResourceSpecificationReq) error { | func AddResourceSpecification(doerId int64, req models.ResourceSpecificationReq) error { | ||||
| @@ -210,14 +213,14 @@ func FindAvailableSpecs(userId int64, opts models.FindSpecsOptions) ([]*models.S | |||||
| return specs, err | return specs, err | ||||
| } | } | ||||
| func FindAvailableSpecs4Show(userId int64, opts models.FindSpecsOptions) ([]*models.SpecificationShow, error) { | |||||
| func FindAvailableSpecs4Show(userId int64, opts models.FindSpecsOptions) ([]*api.SpecificationShow, error) { | |||||
| specs, err := FindAvailableSpecs(userId, opts) | specs, err := FindAvailableSpecs(userId, opts) | ||||
| if err != nil { | if err != nil { | ||||
| return nil, err | return nil, err | ||||
| } | } | ||||
| result := make([]*models.SpecificationShow, len(specs)) | |||||
| result := make([]*api.SpecificationShow, len(specs)) | |||||
| for i, v := range specs { | for i, v := range specs { | ||||
| result[i] = v.ToShow() | |||||
| result[i] = convert.ToSpecification(v) | |||||
| } | } | ||||
| return result, nil | return result, nil | ||||
| } | } | ||||