package dto import ( "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/net/ghttp" "github.com/gogf/gf/v2/os/gtime" ) // 模型训练体系接口(数据集 → 标注 → 训练 → 模型版本),组前缀 /api/v1/admin。 // 图片/标注/模型文件均在服务器磁盘(app.datasetDir),DB 只存元数据。 // 图片访问为直接写响应体场景,由 controller 以 *ghttp.Request 方法实现 // (见 controller/admin.go 的 Image 方法)。 // ---------- 数据集管理 ---------- // AdminDatasetListReq 数据集列表(创建时间倒序) type AdminDatasetListReq struct { g.Meta `path:"/datasets" method:"get" summary:"数据集列表" tags:"管理端"` Keyword string `json:"keyword" v:"length:0,50" dc:"名称模糊匹配"` Page int `json:"page" v:"integer|min:1" dc:"页码,默认 1"` Size int `json:"size" v:"integer|min:1|max:100" dc:"每页条数,默认 20"` } // AdminDatasetItem 数据集条目(卡片展示用;AI 端点/训练机 SSH 走 config.yml 全局配置(localAi / training.ssh)) type AdminDatasetItem struct { Id int64 `json:"id"` Name string `json:"name"` Source string `json:"source"` // manual | ai ImageCount int64 `json:"imageCount"` LabeledCount int64 `json:"labeledCount"` Status string `json:"status"` // building | labeled | synced Cover string `json:"cover"` // 封面文件名 Description string `json:"description"` // 描述 NamePrefix string `json:"namePrefix"` // AI 生成图文件名前缀 TrainingId int64 `json:"trainingId"` // 最新训练记录 id(发布/详情用) TrainingStatus string `json:"trainingStatus"` // 最新训练记录状态 running|success|failed|空 TrainingError string `json:"trainingError"` // 最新训练记录失败原因(failed 时展示用) TrainingPublished bool `json:"trainingPublished"` // 该训练是否已发布过版本(已发布不再显示发布按钮) TrainingCurrentEpoch int `json:"trainingCurrentEpoch"` TrainingTotalEpochs int `json:"trainingTotalEpochs"` CreatedAt *gtime.Time `json:"createdAt"` UpdatedAt *gtime.Time `json:"updatedAt"` } type AdminDatasetListRes struct { Total int64 `json:"total"` List []*AdminDatasetItem `json:"list"` } // AdminDatasetUpdateReq 更新数据集配置(空值字段不覆盖原值,保留现有配置;改名时同步迁移 // 图片目录与模型文件,名称唯一且同是磁盘目录名; // AI 端点/训练机 SSH 走 config.yml 全局配置(localAi / training.ssh)) type AdminDatasetUpdateReq struct { g.Meta `path:"/datasets/update" method:"post" summary:"更新数据集配置" tags:"管理端"` Id int64 `json:"id" v:"required|min:1" dc:"数据集 id"` Name string `json:"name" v:"length:0,50" dc:"数据集名称(非空且变化才更新;同是目录名)"` NamePrefix string `json:"namePrefix" v:"length:0,50" dc:"AI 生成图文件名前缀(非空才更新)"` Description string `json:"description" v:"length:0,500" dc:"描述(非空才更新)"` Cover string `json:"cover" v:"length:0,200" dc:"封面文件名(非空才更新)"` } type AdminDatasetUpdateRes struct { Id int64 `json:"id"` } // AdminDatasetCreateReq 新建数据集(名称同时是磁盘目录名:中文/字母/数字/下划线/短横线,唯一) type AdminDatasetCreateReq struct { g.Meta `path:"/datasets" method:"post" summary:"新建数据集" tags:"管理端"` Name string `json:"name" v:"required|regex:^[a-zA-Z0-9_一-龥-]+$|length:1,50" dc:"数据集名称(同是目录名,唯一)"` Source string `json:"source" v:"required|in:manual,ai" dc:"图片来源 manual|ai"` NamePrefix string `json:"namePrefix" v:"length:0,50" dc:"AI 生成图文件名前缀(可选,字母/数字/下划线/短横线)"` } type AdminDatasetCreateRes struct { Id int64 `json:"id"` } // AdminDatasetDeleteReq 删除数据集(删除图片文件+标注目录+记录;AI 生成图为付费资产,前端须带确认文案) type AdminDatasetDeleteReq struct { g.Meta `path:"/datasets/delete" method:"post" summary:"删除数据集" tags:"管理端"` Id int64 `json:"id" v:"required|min:1" dc:"数据集 id"` } type AdminDatasetDeleteRes struct{} // AdminDatasetUploadReq 上传图片(multipart 多文件;重名跳过并计数) type AdminDatasetUploadReq struct { g.Meta `path:"/datasets/upload" method:"post" summary:"上传图片" tags:"管理端" mime:"multipart/form-data"` DatasetId int64 `json:"datasetId" v:"required|min:1" dc:"数据集 id"` Files []*ghttp.UploadFile `json:"files" dc:"图片文件(jpg/jpeg/png,多选)"` } type AdminDatasetUploadRes struct { Added int `json:"added"` Skipped int `json:"skipped"` // 重名跳过数 } // AdminDatasetGenerateReq AI 生成图片(同步执行;prompt 可手填覆盖模板,禁止含目标位置描述; // 未手填走 imageGen.promptTemplate 组装:species 用表单选择(scene/action/light 随机),数量词=animalCount。 // animalCount 仅作为标注框数上限存储(自动标注按置信度裁剪 ≤N),不参与生成校验; // 距离校验已取消(2026-08-28)。文件名前缀为数据集属性(datasets 表 name_prefix) type AdminDatasetGenerateReq struct { g.Meta `path:"/datasets/generate" method:"post" summary:"AI 生成图片" tags:"管理端"` DatasetId int64 `json:"datasetId" v:"required|min:1" dc:"数据集 id"` Species string `json:"species" v:"length:0,50" dc:"动物名称(如家鸽/山斑鸠;留空按数据集名取物种池随机)"` Prompt string `json:"prompt" v:"length:0,500" dc:"完整提示词(可选,填写则覆盖模板;禁止含位置描述)"` Count int `json:"count" v:"required|integer|min:1|max:8" dc:"生成张数 1-8"` Size string `json:"size" v:"required|in:704x1248" dc:"图片尺寸"` Distance int `json:"distance" v:"required|min:1" dc:"目标距离(米,固定值,注入提示词)"` } // AdminDatasetGenOptionsReq 生成表单选项(物种池/场景池,来自 config imageGen 配置) type AdminDatasetGenOptionsReq struct { g.Meta `path:"/datasets/gen-options" method:"get" summary:"生成表单选项" tags:"管理端"` DatasetId int64 `json:"datasetId" v:"required|min:1" dc:"数据集 id"` } type AdminDatasetGenOptionsRes struct { Species []string `json:"species"` // 该数据集的物种池(未配置则为空,表单可自由输入) Scenes []string `json:"scenes"` // 环境场景池 } type AdminDatasetGenerateRes struct { Generated int `json:"generated"` // 成功入库张数(校验不合格的已跳过) Rejected int `json:"rejected"` // 连续 N 次校验不合格被跳过的张数 } // AdminDatasetImagesReq 数据集图片列表(标注工作台/网格预览用) type AdminDatasetImagesReq struct { g.Meta `path:"/datasets/images" method:"get" summary:"数据集图片列表" tags:"管理端"` DatasetId int64 `json:"datasetId" v:"required|min:1" dc:"数据集 id"` } // AdminImageItem 图片条目(url 为管理端图片访问地址,前端拼 apiBaseUrl 使用) type AdminImageItem struct { Id int64 `json:"id"` Filename string `json:"filename"` Source string `json:"source"` // manual | ai Prompt string `json:"prompt"` Url string `json:"url"` CreatedAt *gtime.Time `json:"createdAt"` } type AdminDatasetImagesRes struct { List []*AdminImageItem `json:"list"` } // AdminDatasetImagesDeleteReq 删除图片(删文件+删记录;付费资产,前端须带确认文案) type AdminDatasetImagesDeleteReq struct { g.Meta `path:"/datasets/images/delete" method:"post" summary:"删除图片" tags:"管理端"` DatasetId int64 `json:"datasetId" v:"required|min:1" dc:"数据集 id"` Ids []int64 `json:"ids" v:"required|min-length:1" dc:"图片记录 id 列表"` } type AdminDatasetImagesDeleteRes struct{} // AdminDatasetImageReq 图片访问(直写响应体,例外场景:controller 经 service 校验归属后输出二进制) type AdminDatasetImageReq struct { g.Meta `path:"/datasets/image" method:"get" summary:"图片访问" tags:"管理端"` DatasetId int64 `json:"datasetId" v:"required|min:1" dc:"数据集 id"` Filename string `json:"filename" v:"required" dc:"图片文件名"` } type AdminDatasetImageRes struct{} // AdminDatasetCoverUploadReq 上传数据集封面(multipart 单文件;覆盖旧封面,UUID 命名 jpg) type AdminDatasetCoverUploadReq struct { g.Meta `path:"/datasets/cover" method:"post" summary:"上传数据集封面" tags:"管理端" mime:"multipart/form-data"` DatasetId int64 `json:"datasetId" v:"required|min:1" dc:"数据集 id"` File *ghttp.UploadFile `json:"file" dc:"封面图片(jpg/jpeg/png,≤2MB)"` } type AdminDatasetCoverUploadRes struct{} // AdminDatasetCoverReq 封面访问(直写响应体,与 Image 同模式) type AdminDatasetCoverReq struct { g.Meta `path:"/datasets/cover" method:"get" summary:"数据集封面访问" tags:"管理端"` DatasetId int64 `json:"datasetId" v:"required|min:1" dc:"数据集 id"` } type AdminDatasetCoverRes struct{} // AdminDatasetCoverDeleteReq 删除数据集封面(删文件+清字段;列表卡片恢复占位图) type AdminDatasetCoverDeleteReq struct { g.Meta `path:"/datasets/cover/delete" method:"post" summary:"删除数据集封面" tags:"管理端"` DatasetId int64 `json:"datasetId" v:"required|min:1" dc:"数据集 id"` } type AdminDatasetCoverDeleteRes struct{} // ---------- 训练编排 ---------- // AdminTrainingListReq 训练任务列表(创建时间倒序) type AdminTrainingListReq struct { g.Meta `path:"/trainings" method:"get" summary:"训练任务列表" tags:"管理端"` Status string `json:"status" v:"in:running,success,failed" dc:"状态筛选"` Page int `json:"page" v:"integer|min:1" dc:"页码,默认 1"` Size int `json:"size" v:"integer|min:1|max:100" dc:"每页条数,默认 20"` } // AdminTrainingItem 训练任务条目(列表不含日志尾部,详情接口返回) type AdminTrainingItem struct { Id int64 `json:"id"` Name string `json:"name"` DatasetId int64 `json:"datasetId"` DatasetName string `json:"datasetName"` Status string `json:"status"` // running | success | failed Imgsz int `json:"imgsz"` Epochs int `json:"epochs"` Batch int `json:"batch"` Device string `json:"device"` CurrentEpoch int `json:"currentEpoch"` TotalEpochs int `json:"totalEpochs"` Metrics string `json:"metrics"` Error string `json:"error"` StartedAt *gtime.Time `json:"startedAt"` FinishedAt *gtime.Time `json:"finishedAt"` CreatedAt *gtime.Time `json:"createdAt"` } type AdminTrainingListRes struct { Total int64 `json:"total"` List []*AdminTrainingItem `json:"list"` } // AdminTrainingStartReq 发起训练(并发度 1:已有 running 任务时拒绝;训练参数走 config.yml training 节点,name 空则自动生成) type AdminTrainingStartReq struct { g.Meta `path:"/trainings" method:"post" summary:"发起训练" tags:"管理端"` DatasetId int64 `json:"datasetId" v:"required|min:1" dc:"数据集 id"` Name string `json:"name" v:"length:0,50" dc:"任务名称,空自动生成"` } type AdminTrainingStartRes struct { Id int64 `json:"id"` } // AdminTrainingDetailReq 训练任务详情(含日志尾部) type AdminTrainingDetailReq struct { g.Meta `path:"/trainings/detail" method:"get" summary:"训练任务详情" tags:"管理端"` Id int64 `json:"id" v:"required|min:1" dc:"训练任务 id"` } // AdminTrainingDetailRes 详情 = 条目 + 日志尾部 type AdminTrainingDetailRes struct { AdminTrainingItem LogTail string `json:"logTail"` } // AdminTrainingCancelReq 取消训练(杀进程,任务置 failed) type AdminTrainingCancelReq struct { g.Meta `path:"/trainings/cancel" method:"post" summary:"取消训练" tags:"管理端"` Id int64 `json:"id" v:"required|min:1" dc:"训练任务 id"` } type AdminTrainingCancelRes struct{} // AdminTrainingPublishReq 发布模型版本(仅 success 任务;按数据集版本号 m.. 自增) type AdminTrainingPublishReq struct { g.Meta `path:"/trainings/publish" method:"post" summary:"发布模型版本" tags:"管理端"` Id int64 `json:"id" v:"required|min:1" dc:"训练任务 id"` } type AdminTrainingPublishRes struct { Version string `json:"version"` } // ---------- 模型版本 ---------- // ---------- 预标注 ---------- // AdminLabelTaskListReq 预标注任务列表(创建时间倒序) type AdminLabelTaskListReq struct { g.Meta `path:"/label-tasks" method:"get" summary:"预标注任务列表" tags:"管理端"` Page int `json:"page" v:"integer|min:1" dc:"页码,默认 1"` Size int `json:"size" v:"integer|min:1|max:100" dc:"每页条数,默认 20"` } type AdminLabelTaskItem struct { Id int64 `json:"id"` DatasetId int64 `json:"datasetId"` DatasetName string `json:"datasetName"` Status string `json:"status"` // running | done Total int `json:"total"` Done int `json:"done"` Error string `json:"error"` CreatedAt *gtime.Time `json:"createdAt"` FinishedAt *gtime.Time `json:"finishedAt"` } type AdminLabelTaskListRes struct { Total int64 `json:"total"` List []*AdminLabelTaskItem `json:"list"` } // AdminLabelTaskStartReq 发起预标注(RF-DETR 扫描,候选框合并入 datasets//boxes.json) type AdminLabelTaskStartReq struct { g.Meta `path:"/label-tasks" method:"post" summary:"发起预标注" tags:"管理端"` DatasetId int64 `json:"datasetId" v:"required|min:1" dc:"数据集 id"` Filenames []string `json:"filenames" v:"length:0,500" dc:"选中图片列表(多选批量);缺省=全量扫描"` } type AdminLabelTaskStartRes struct { Id int64 `json:"id"` } // AdminImageVlmReviewReq 单图 VLM 补检:qwen3.8-9b 按「环境/光线/习性」推理 RF-DETR 之外 // 可能藏匿目标的位置(排除已确认坐标),最多补 3 个疑似框(class 1)追加到 labels_json。 // 依赖 localAi.vlmModel(默认 qwen3.8-9b);VL 与 z-image 生成不能同时驻留显存,批量补检 // 应在生成队列空闲时执行 type AdminImageVlmReviewReq struct { g.Meta `path:"/datasets/images/vlm-review" method:"post" summary:"VLM 藏匿位补检" tags:"管理端"` DatasetId int64 `json:"datasetId" v:"required|min:1" dc:"数据集 id"` ImageId int64 `json:"imageId" v:"required|min:1" dc:"图片 id"` } type AdminImageVlmReviewRes struct { Added int `json:"added"` // 新增疑似框数(≤3) Boxes []*AdminLabelBox `json:"boxes"` // VLM 新增框(归一化坐标,class=1) Note string `json:"note"` // 未补检原因(如已确认框为空/VL 无输出) } // AdminLabelTaskDetailReq 预标注任务详情(每张图候选框 + 已确认标注,供工作台 canvas 叠框) type AdminLabelTaskDetailReq struct { g.Meta `path:"/label-tasks/detail" method:"get" summary:"预标注任务详情" tags:"管理端"` Id int64 `json:"id" v:"required|min:1" dc:"标注任务 id"` } // AdminLabelBox 单框(归一化 xywh,坐标 0~1) type AdminLabelBox struct { Cx float64 `json:"cx"` Cy float64 `json:"cy"` W float64 `json:"w"` H float64 `json:"h"` Confidence float64 `json:"confidence"` // 人工框为 1 Class int `json:"class"` // 0 确认 | 1 疑似 } // AdminLabelImageItem 工作台单张图:全部标注(labels_json,AI 自动标注与人工框同层,人工可修改/清理) type AdminLabelImageItem struct { Filename string `json:"filename"` Url string `json:"url"` Width int `json:"width"` Height int `json:"height"` Boxes []*AdminLabelBox `json:"boxes"` Labeled bool `json:"labeled"` // 有标注(AI 自动标注或人工保存) } type AdminLabelTaskDetailRes struct { TaskId int64 `json:"taskId"` DatasetId int64 `json:"datasetId"` DatasetName string `json:"datasetName"` Status string `json:"status"` Total int `json:"total"` Done int `json:"done"` Error string `json:"error"` Images []*AdminLabelImageItem `json:"images"` } // AdminLabelWorkbenchReq 标注工作台数据(无历史任务时直接用数据集图片 + 已确认标注, // 候选框读数据集目录 boxes.json) type AdminLabelWorkbenchReq struct { g.Meta `path:"/label-workbench" method:"get" summary:"标注工作台数据" tags:"管理端"` DatasetId int64 `json:"datasetId" v:"required|min:1" dc:"数据集 id"` } type AdminLabelWorkbenchRes struct { DatasetId int64 `json:"datasetId"` DatasetName string `json:"datasetName"` Images []*AdminLabelImageItem `json:"images"` } // AdminLabelSaveReq 保存单张图标注(工作台「保存本张」;覆写 dataset_image.labels_json) type AdminLabelSaveReq struct { g.Meta `path:"/label-tasks/save" method:"post" summary:"保存图片标注" tags:"管理端"` DatasetId int64 `json:"datasetId" v:"required|min:1" dc:"数据集 id"` Filename string `json:"filename" v:"required|length:1,200" dc:"图片文件名"` Boxes []*AdminLabelBox `json:"boxes" dc:"确认后的框列表(空=清空标注)"` } type AdminLabelSaveRes struct { LabeledCount int64 `json:"labeledCount"` // 该数据集当前已标注图数 } // ---------- 客户端模型目录 ---------- // ModelCatalogReq 模型目录(客户端登录态):全部数据集的当前生效模型 type ModelCatalogReq struct { g.Meta `path:"/models" method:"get" summary:"模型目录" tags:"客户端"` } // ModelCatalogItem 客户端模型条目(App 按需下载,多模型并行推理合并) type ModelCatalogItem struct { DatasetId int64 `json:"datasetId"` DatasetName string `json:"datasetName"` Version string `json:"version"` Labels []string `json:"labels"` // 类别名,App 推理结果展示用 SizeBytes int64 `json:"sizeBytes"` Sha256 string `json:"sha256"` Notes string `json:"notes"` PublishedAt *gtime.Time `json:"publishedAt"` DownloadUrl string `json:"downloadUrl"` // /download/trainings/.tflite } type ModelCatalogRes struct { List []*ModelCatalogItem `json:"list"` }