This commit is contained in:
2026-08-28 17:33:35 +08:00
parent ad17e915fc
commit df1eacbda8
21 changed files with 48 additions and 36 deletions
+5 -2
View File
@@ -63,11 +63,14 @@ func (d *datasetImageDao) GetById(ctx context.Context, id int64) (*entity.Datase
return one, nil
}
// ListByDataset 某数据集全部图片(文件名倒序,详情页逐行展示用)
// ListByDataset 某数据集全部图片(文件名编号倒序,详情页逐行展示用)
// 文件名形如 <前缀>_<编号>.jpg(无前缀为时间戳数字名),须提取下划线后的数字按数值倒序:
// 字符串序会把 pheasant_101.jpg 排在 pheasant_2.jpg 之前('1'<'9'),导致最大编号落到底部
func (d *datasetImageDao) ListByDataset(ctx context.Context, datasetId int64) ([]*entity.DatasetImage, error) {
var list []*entity.DatasetImage
err := g.DB().Model(consts.TableDatasetImage).Ctx(ctx).
Where("dataset_id", datasetId).OrderDesc("filename").Scan(&list)
Where("dataset_id", datasetId).
Order("CAST(substr(filename, instr(filename, '_') + 1) AS INTEGER) DESC").Scan(&list)
if err != nil {
if common.IsNoRows(err) {
return []*entity.DatasetImage{}, nil
+4 -1
View File
@@ -609,6 +609,8 @@ func (s *datasetService) buildPromptFromTemplate(ctx context.Context, datasetNam
scene := pickCfgByDataset(ctx, datasetName, "imageGen.sceneByDataset", "imageGen.scenes")
action := pickCfgByDataset(ctx, datasetName, "imageGen.actionByDataset", "imageGen.actions")
light := pickCfg(ctx, "imageGen.lights")
// 轮廓色词按物种(白化个体如白雉鸡配浅色,默认深色剪影)
tone := g.Cfg().MustGet(ctx, "imageGen.speciesTone."+species, "深色").String()
// 距离描述从表单固定值生成(25 → "25米外"
distWord := fmt.Sprintf("%d米外", dist)
// 尺寸提示:按物理公式把表单距离换算成目标在图中的像素高与画面占比
@@ -622,6 +624,7 @@ func (s *datasetService) buildPromptFromTemplate(ctx context.Context, datasetNam
for k, v := range map[string]string{
"{scene}": scene, "{species}": species, "{count}": countWord,
"{action}": action, "{light}": light, "{distanceWord}": distWord, "{sizeHint}": sizeHint,
"{tone}": tone,
} {
out = strings.ReplaceAll(out, k, v)
}
@@ -722,7 +725,7 @@ func (s *datasetService) AdminGenerateImages(ctx context.Context, req *dto.Admin
return provider.Generate(genCtx, prompt, req.Size)
}
// 命名:数据集属性 name_prefix(创建/编辑表单维护)非空时按 <前缀>_<两位序号>.jpg 顺序编号
// (延续数据集内已有最大序号,参考野鸡目录 pheasant_NN.jpg 惯例);无前缀按时间戳命名。
// (延续数据集内已有最大序号,参考既有图片目录的连续编号惯例);无前缀按时间戳命名。
// 注意:gtime.Time.Format 是 PHP 风格格式符,Go 数字布局须用 .Time.Format,否则原样透传
prefix := dataset.NamePrefix
nextIdx := 1
+12 -6
View File
@@ -40,16 +40,20 @@ imageGen:
timeoutSeconds: 600 # 每张生成超时(默认 120z-image-turbo 首次加载含模型入显存,稳态秒级~分钟级)
# 通用提示词模板(管理端填「动物名称」时启用,每张随机取池组装):{species} 优先用表单填写的名称,
# 未填则按数据集名取 speciesByDataset 池(再未配置直接用数据集名);{count} 为数量词(固定 "1只",每张仅 1 个目标;原表单
# 数量选择已取消);{scene}/{action}/{light} 池内随机;物种只写名字不写羽毛细节
# (细节会把镜头拉近,详见技术设计)。不带拍摄角度描述(2026-08-28):角度描述会与目标位置耦合,
# 仰拍使贴地目标沉底、固定俯拍构图单一——交由模型平视先验自由构图,目标自然落在中部/上部
promptTemplate: "野外大远景实拍:广角镜头下{scene}{distanceWord}有且仅有{count}{species}的小小身影{sizeHint}在{action}{species}离镜头很远,只是很小的深色轮廓,隐约可辨,画面绝大部分是{scene},没有任何靠近镜头的动物,{light},写实野外摄影,真实照片质感"
# 数量选择已取消);{scene}/{action}/{light} 池内随机;{tone} 为物种轮廓色词(默认深色,白化个体配浅色);
# 物种只写名字不写羽毛细节(细节会把镜头拉近,详见技术设计)。不带拍摄角度描述(2026-08-28):
# 角度描述会与目标位置耦合,仰拍使贴地目标沉底、固定俯拍构图单一——交由模型平视先验自由构图,
# 目标自然落在中部/上部
promptTemplate: "野外大远景实拍:广角镜头下{scene}{distanceWord}有且仅有{count}{species}的小小身影{sizeHint}在{action}{species}离镜头很远,只是很小的{tone}轮廓,隐约可辨,画面绝大部分是{scene},没有任何靠近镜头的动物,{light},写实野外摄影,真实照片质感"
speciesByDataset: # 数据集名 → 物种池(表单未填动物名称时随机取一个)
鸽子: [家鸽,火斑鸠,虎纹斑鸠,珠颈斑鸠,灰斑鸠]
雉鸡: [雉鸡]
雉鸡: [雉鸡,白雉鸡]
兔子: [兔子]
鸭子: [野鸭]
鹌鹑: [鹌鹑]
speciesTone: # 物种轮廓色词(模板 {tone} 占位,未配置默认深色):远景小目标深色剪影易辨,
# 白化个体(白雉鸡)用「深色轮廓」描述与白色羽毛矛盾,须配浅色
白雉鸡: 浅色
scenes: # 环境场景池(统一远景原则:每条含开阔/延伸向远方/地平线元素,
# 把地平线推开、消除近拍暗示;同一短语在模板中出现两次,须两处都读得通)
- "一望无际的玉米地,玉米秆两米多高,田间土路和田埂延伸向地平线"
@@ -70,6 +74,7 @@ imageGen:
- "田边茂密的草丛和矮灌丛连绵延伸到远方"
- "荒草坡和灌木丛连成一片,一直铺向远处地平线"
- "收割后的农田边缘杂草丛生,矮灌丛点缀延伸到远方"
- "稀疏灌木点缀的草坡,一直延伸到远处的林地边缘"
兔子:
- "枯黄的草坡和荒草地一直延伸到远方"
- "弃耕地和田埂长满野草,延伸向远处的林地"
@@ -98,7 +103,8 @@ imageGen:
灰斑鸠: 18
火斑鸠: 15
虎纹斑鸠: 18
: 55
: 55
白雉鸡: 55
兔子: 35
野鸭: 35
鹌鹑: 12
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

+1 -1
View File
@@ -332,7 +332,7 @@ Android 客户端启动 GET /api/v1/app/update(公开,无需 tokeniOS 不
- 生成同步执行(count 1..8,每张超时 `imageGen.timeoutSeconds`,默认 120slocalai 建议 600),逐张落盘 + 入库(记录 prompt 便于追溯);中途失败返回错误(已成功的图保留,不删除——付费资产原则)
- prompt 手填覆盖;留空走 `imageGen.promptTemplate` 通用模板逐张组装(物种池 speciesByDataset 按数据集名、数量词=animalCount、场景/动作/光线池随机,每张独立组装保持多样性;物种只写名字不写羽毛细节,细节会拉近镜头);**遵守项目提示词规范:不得包含目标位置描述**(位置由模型自行推理,前端模板与校验文案落实此约束)
- **生成图距离/数量校验(2026-08-28)**:表单填 `distance`(米,固定值) 与 `animalCount` 后逐张启用;**距离校验已取消(2026-08-28)**:生成即入库,无逐张拒检;参数与公式见 git 历史(物理公式 d=体高×focalPx÷像素高)
- **VLM 藏匿位补检(两阶段第二阶段)**:`/datasets/images/vlm-review` 单图接口;qwen3.8-9b(+mmproj) 以「图片+物种(生成 prompt 与物种池匹配)+场景光线线索+已确认框坐标(排除)」推理藏匿位,输出归一化 bbox JSON(范围校验+与已有框重叠去重),追加 ≤3 个 class=1 疑似框进同一 labels_jsonVL 与 z-image 显存互斥(12G 装不下两者),批量补检在生成队列空闲后执行;qwen3.8-9b yaml 自带 mmproj 实为多模态模型(生成校验);自动标注框数按置信度降序裁剪 ≤ animal_count(存 dataset_image.animal_count 列),估算距离 = 物种站高 × focalPx ÷ 最大框高像素(focalPx=`图高/2/tan(vfov/2)`,站高按物种查 `imageGen.speciesHeights`,单位 cm 换算为米,未配置物种代码兜底 35cm;**2026-08-28 语义修正**speciesHeights 为站高(垂直尺度,鸟=脚到头顶、兽=蹲坐高),勿用体长——与提示词「高度」描述及检测框高自洽;避免跨物种共用一个标定系数)(K=1.8:6%≈30m、4.5%≈40m,K 隐含镜头视场角假设);**镜头固定主摄(2026-08-28 定案)**vfov 固定 `imageGen.assumedVfovDeg=52°`(手机默认主摄;曾随机 [15,90] 覆盖面广但目标像素波动 7~57px 不可控,曾试超广角 90 亦否决);**场景/动作按数据集(2026-08-28**`imageGen.sceneByDataset`/`actionByDataset` 按数据集名配池(鸭→水面、雉鸡→灌丛草丛、兔→草坡荒地、鹌鹑→草丛),未配置回退通用 scenes/actions**拍摄角度(2026-08-28,已废弃角度描述)**:不带任何拍摄角度描述——演进:固定「上部三分之一」区域描述对文生图模型遵循力弱(生成物落底)→ 加固定俯拍(目标上移成功但构图单一,用户否决)→ 池内随机俯/平/仰(仰拍使贴地目标必然沉底,用户否决)→ 只留俯拍/平视(用户仍嫌啰嗦)→ **完全去掉角度描述**2026-08-28 定案):交由模型平视先验自由构图,目标自然落在画面中部/上部;模板只靠「{species}离镜头很远,只是很小的深色轮廓」(物种名替代泛称「目标」,不限定鸟类——物种池含兔子等非鸟物种)维持远景感,手填提示词仅追加数量约束;不合格丢弃重生成,单张上限 3 次(`consts.GenValidateMaxAttempts`),连续不合格整体报错(已合格张数保留)
- **VLM 藏匿位补检(两阶段第二阶段)**:`/datasets/images/vlm-review` 单图接口;qwen3.8-9b(+mmproj) 以「图片+物种(生成 prompt 与物种池匹配)+场景光线线索+已确认框坐标(排除)」推理藏匿位,输出归一化 bbox JSON(范围校验+与已有框重叠去重),追加 ≤3 个 class=1 疑似框进同一 labels_jsonVL 与 z-image 显存互斥(12G 装不下两者),批量补检在生成队列空闲后执行;qwen3.8-9b yaml 自带 mmproj 实为多模态模型(生成校验);自动标注框数按置信度降序裁剪 ≤ animal_count(存 dataset_image.animal_count 列),估算距离 = 物种站高 × focalPx ÷ 最大框高像素(focalPx=`图高/2/tan(vfov/2)`,站高按物种查 `imageGen.speciesHeights`,单位 cm 换算为米,未配置物种代码兜底 35cm;**2026-08-28 语义修正**speciesHeights 为站高(垂直尺度,鸟=脚到头顶、兽=蹲坐高),勿用体长——与提示词「高度」描述及检测框高自洽;避免跨物种共用一个标定系数)(K=1.8:6%≈30m、4.5%≈40m,K 隐含镜头视场角假设);**镜头固定主摄(2026-08-28 定案)**vfov 固定 `imageGen.assumedVfovDeg=52°`(手机默认主摄;曾随机 [15,90] 覆盖面广但目标像素波动 7~57px 不可控,曾试超广角 90 亦否决);**场景/动作按数据集(2026-08-28**`imageGen.sceneByDataset`/`actionByDataset` 按数据集名配池(鸭→水面、雉鸡→灌丛草丛、兔→草坡荒地、鹌鹑→草丛),未配置回退通用 scenes/actions**拍摄角度(2026-08-28,已废弃角度描述)**:不带任何拍摄角度描述——演进:固定「上部三分之一」区域描述对文生图模型遵循力弱(生成物落底)→ 加固定俯拍(目标上移成功但构图单一,用户否决)→ 池内随机俯/平/仰(仰拍使贴地目标必然沉底,用户否决)→ 只留俯拍/平视(用户仍嫌啰嗦)→ **完全去掉角度描述**2026-08-28 定案):交由模型平视先验自由构图,目标自然落在画面中部/上部;模板只靠「{species}离镜头很远,只是很小的{tone}轮廓」(物种名替代泛称「目标」,不限定鸟类——物种池含兔子等非鸟物种`{tone}` 轮廓色词按 `imageGen.speciesTone.<物种>` 取,默认深色剪影,**白雉鸡配浅色**——白羽个体用「深色轮廓」描述会与模型渲染矛盾,2026-08-28)维持远景感,手填提示词仅追加数量约束;不合格丢弃重生成,单张上限 3 次(`consts.GenValidateMaxAttempts`),连续不合格整体报错(已合格张数保留)
### 训练通道(runner 抽象,决策:同机/异机不确定 → 可配置)