Files
observer/server/biz/model/dto/training.go
T

466 lines
23 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 生成图文件名前缀
GenSpecies string `json:"genSpecies"` // 生成参数池:物种(单值)
GenTone string `json:"genTone"` // 轮廓色词(单值)
GenHeights float64 `json:"genHeights"` // 站高cm(数值)
GenScenes string `json:"genScenes"` // 场景池(JSON 数组)
GenActions string `json:"genActions"` // 动作池(JSON 数组)
GenOcclusions string `json:"genOcclusions"` // 遮挡池(JSON 数组)
GenClasses string `json:"genClasses"` // 第二标注类别名(单值)
SortOrder int64 `json:"sortOrder"` // 序号(列表排序主键,升序)
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)。
// gen_* 7 列(species/tone/heights/scenes/actions/occlusions/classes)不在此维护——
// 创建数据集时 VLM 生成,重新生成走 gen-pools 接口
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:"封面文件名(非空才更新)"`
SortOrder *int64 `json:"sortOrder" dc:"序号(升序排列,缺省不更新)"`
}
type AdminDatasetUpdateRes struct {
Id int64 `json:"id"`
}
// AdminDatasetCreateReq 新建数据集(名称同时是磁盘目录名:中文/字母/数字/下划线/短横线,唯一;
// 单物种规则:数据集名即物种,VLM 按数据集名自动生成生成参数池,表单无动物名称输入)
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 生成图文件名前缀(可选,字母/数字/下划线/短横线)"`
Cover string `json:"cover" v:"length:0,200" dc:"封面文件名(新建对话框预生成封面后回传;非空则跳过自动生成)"`
SortOrder *int64 `json:"sortOrder" dc:"序号(列表排序主键,升序;缺省 0)"`
}
type AdminDatasetCreateRes struct {
Id int64 `json:"id"`
PoolsGenerated bool `json:"poolsGenerated"` // 是否已用 VLM 生成生成参数池
PoolError string `json:"poolError"` // 参数池生成失败原因(可用 gen-pools 补生成)
CoverGenerated bool `json:"coverGenerated"` // 是否已生成封面(16:9、1雄1雌)
CoverError string `json:"coverError"` // 封面生成失败原因(可编辑模式重新生成)
}
// AdminGenPoolsReq 重新生成生成参数池(VLM 覆盖写;编辑对话框「VLM 重新生成参数」入口,
// 按数据集名生成——单物种规则,无动物名称输入)
type AdminGenPoolsReq struct {
g.Meta `path:"/datasets/gen-pools" method:"post" summary:"重新生成生成参数池" tags:"管理端"`
DatasetId int64 `json:"datasetId" v:"required|min:1" dc:"数据集 id"`
}
type AdminGenPoolsRes struct {
GenSpecies string `json:"genSpecies"`
GenTone string `json:"genTone"`
GenHeights float64 `json:"genHeights"`
GenScenes string `json:"genScenes"`
GenActions string `json:"genActions"`
GenOcclusions string `json:"genOcclusions"`
GenClasses string `json:"genClasses"`
}
// 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 组装(单物种规则:物种固定取数据集 gen_species[0]/数据集名,
// 表单无物种输入),scene/action/occlusion 从数据集表池随机。
// animalCount 仅作为标注框数上限存储(自动标注按置信度裁剪 ≤N),不参与生成校验;
// 距离校验已取消(2026-08-28)。文件名前缀为数据集属性(datasets 表 name_prefix)。
// 生成耗时约 40s/张(localai),批量请用返回的 TaskId 轮询 /datasets/gen-task 进度。
type AdminDatasetGenerateReq struct {
g.Meta `path:"/datasets/generate" method:"post" summary:"AI 生成图片(异步任务)" tags:"管理端"`
DatasetId int64 `json:"datasetId" v:"required|min:1" dc:"数据集 id"`
Prompt string `json:"prompt" v:"length:0,500" dc:"完整提示词(可选,填写则覆盖模板;禁止含位置描述)"`
Count int `json:"count" v:"required|integer|min:1|max:1000" dc:"生成张数 1-1000"`
Size string `json:"size" v:"required|in:704x1248" dc:"图片尺寸"`
Distance int `json:"distance" v:"required|min:1" dc:"目标距离(米,固定值,注入提示词)"`
}
type AdminDatasetGenerateRes struct {
TaskId int64 `json:"taskId"` // 生成任务 id(前端轮询 /datasets/gen-task 进度)
Total int `json:"total"` // 计划生成张数
}
// AdminGenTaskQueryReq 生成任务进度查询(前端轮询;任务完成后错误信息在 Error)
type AdminGenTaskQueryReq struct {
g.Meta `path:"/datasets/gen-task" method:"get" summary:"生成任务进度" tags:"管理端"`
DatasetId int64 `json:"datasetId" v:"required|min:1" dc:"数据集 id"`
}
type AdminGenTaskQueryRes struct {
Id int64 `json:"id"`
DatasetId int64 `json:"datasetId"`
Status string `json:"status"` // running | done | failed
Total int `json:"total"`
Done int `json:"done"`
Error string `json:"error"`
CreatedAt *gtime.Time `json:"createdAt"`
FinishedAt *gtime.Time `json:"finishedAt"`
}
// 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 同模式;
// datasetId=0 时按 name+filename 直读——新建对话框预生成封面回显用)
type AdminDatasetCoverReq struct {
g.Meta `path:"/datasets/cover" method:"get" summary:"数据集封面访问" tags:"管理端"`
DatasetId int64 `json:"datasetId" v:"min:0" dc:"数据集 id"`
Name string `json:"name" v:"length:0,50" dc:"数据集名称(datasetId=0 时必填)"`
Filename string `json:"filename" v:"length:0,200" dc:"封面文件名(datasetId=0 时必填)"`
}
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{}
// AdminGenCoverReq 生成数据集封面(z-image 文生图:16:9、1 雄 1 雌;覆盖旧封面;编辑对话框按钮入口)。
// datasetId=0 时按 name 预生成(新建对话框——数据集未创建,封面仅落盘不写库,
// 创建请求带 cover 回传写库),物种取数据集名。
type AdminGenCoverReq struct {
g.Meta `path:"/datasets/cover/generate" method:"post" summary:"生成数据集封面" tags:"管理端"`
DatasetId int64 `json:"datasetId" v:"min:0" dc:"数据集 id(0=新建预生成)"`
Name string `json:"name" v:"length:0,50" dc:"数据集名称(datasetId=0 时必填)"`
}
type AdminGenCoverRes struct {
Cover string `json:"cover" dc:"新封面文件名"`
}
// ---------- 训练编排 ----------
// 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<major>.<minor>.<patch> 自增)
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/<name>/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.6-35b-a3b 按「环境/光线/习性」推理 RF-DETR 之外
// 可能藏匿目标的位置(排除已确认坐标),最多补 3 个疑似框(class 1)追加到 labels_json。
// 依赖 localAi.vlmModel(默认 qwen3.6-35b-a3b);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(前缀空回退数据集名)
CoverUrl string `json:"coverUrl"` // /api/v1/app/cover?namePrefix=<前缀>App 模型清单缩略图)
}
type ModelCatalogRes struct {
List []*ModelCatalogItem `json:"list"`
}