package service import ( "context" "encoding/json" "net/url" "observer-server/biz/dao" "observer-server/biz/model/dto" ) // modelVersionService 模型版本业务:管理端无模型管理界面(2026-08-26 决策), // 版本记录仅支撑客户端模型目录(App 多模型下载热更新)。文件布局见 common/workspace.go。 type modelVersionService struct{} var ModelVersion = &modelVersionService{} // ClientCatalog 客户端模型目录:全部数据集当前生效模型(App 多模型下载热更新)。 // downloadUrl 复用 /download 静态托管(/download/trainings/<文件名前缀>.tflite,前缀空回退数据集名)。 func (s *modelVersionService) ClientCatalog(ctx context.Context) (*dto.ModelCatalogRes, error) { list, err := dao.ModelVersion.ListAllLatest(ctx) if err != nil { return nil, err } names := Training.datasetNameMap(ctx) modelNames := Training.datasetModelNameMap(ctx) items := make([]*dto.ModelCatalogItem, 0, len(list)) for _, v := range list { datasetName := names[v.DatasetId] if datasetName == "" { continue } items = append(items, &dto.ModelCatalogItem{ DatasetId: v.DatasetId, DatasetName: datasetName, Version: v.Version, Labels: parseLabels(v.Labels), SizeBytes: v.SizeBytes, Sha256: v.Sha256, Notes: v.Notes, PublishedAt: v.CreatedAt, DownloadUrl: "/download/trainings/" + modelNames[v.DatasetId] + ".tflite", CoverUrl: "/api/v1/app/cover?namePrefix=" + url.PathEscape(modelNames[v.DatasetId]), }) } return &dto.ModelCatalogRes{List: items}, nil } // parseLabels 解析类别名 JSON 数组 func parseLabels(s string) []string { var out []string if err := json.Unmarshal([]byte(s), &out); err != nil || len(out) == 0 { return []string{"class0", "class1"} } return out }