diff --git a/styleagent/model/dto/outfit_generation_task_dto.go b/styleagent/model/dto/outfit_generation_task_dto.go index 86445c5..fb38f46 100644 --- a/styleagent/model/dto/outfit_generation_task_dto.go +++ b/styleagent/model/dto/outfit_generation_task_dto.go @@ -9,6 +9,7 @@ type OutfitGenerateReq struct { StartDate string `v:"required|date" json:"start_date"` EndDate string `v:"required|date" json:"end_date"` Location string `v:"required" json:"location"` + Occasion string `v:"in:通勤,约会,聚会,运动" json:"occasion"` } type OutfitGenerateRes struct { diff --git a/styleagent/service/outfit_generation_task_service.go b/styleagent/service/outfit_generation_task_service.go index 970dc08..18cd092 100644 --- a/styleagent/service/outfit_generation_task_service.go +++ b/styleagent/service/outfit_generation_task_service.go @@ -41,10 +41,18 @@ func (s *outfitService) Generate(ctx context.Context, userId int64, req *dto.Out return 0, err } // 异步执行:传入独立 ctx(请求结束不中断任务) - go runGenerateTask(gctx.New(), taskId, userId) + go runGenerateTask(gctx.New(), taskId, userId, normalizeOccasion(req.Occasion)) return taskId, nil } +// normalizeOccasion 空场景默认通勤(评分引擎按 通勤/约会/聚会/运动 匹配) +func normalizeOccasion(o string) string { + if o == "" { + return "通勤" + } + return o +} + // StartWorker 服务启动时恢复未完成任务(标记失败,避免重启后重复消耗 LLM 费用) func (s *outfitService) StartWorker(ctx context.Context) { tasks, err := dao.OutfitGenTask.ListUnfinished(ctx) @@ -59,7 +67,7 @@ func (s *outfitService) StartWorker(ctx context.Context) { } // runGenerateTask 任务核心流程:planning → scoring → done/failed -func runGenerateTask(ctx context.Context, taskId, userId int64) { +func runGenerateTask(ctx context.Context, taskId, userId int64, occasion string) { setTask := func(status, msg string) { _ = dao.OutfitGenTask.UpdateStatus(ctx, taskId, status, msg) } @@ -109,7 +117,6 @@ func runGenerateTask(ctx context.Context, taskId, userId int64) { // 4. LLM 规划(1 次调用) hairstyles := hairstyleListText(ctx) bodyDesc := bodyDescText(ctx, userId) - occasion := "通勤" candidates := make([]agent.CandidateData, 0, len(sets)*3) for si, set := range sets { for _, it := range set.Items { diff --git a/styleagent/service/outfit_generation_task_service_test.go b/styleagent/service/outfit_generation_task_service_test.go new file mode 100644 index 0000000..6acf085 --- /dev/null +++ b/styleagent/service/outfit_generation_task_service_test.go @@ -0,0 +1,40 @@ +package service + +import ( + "context" + "testing" + + "github.com/gogf/gf/v2/frame/g" + + _ "github.com/gogf/gf/contrib/drivers/sqlite/v2" + "slogan-agent/styleagent/model/dto" +) + +func TestGenerateReqOccasionValidation(t *testing.T) { + valid := []string{"", "通勤", "约会", "聚会", "运动"} + for _, v := range valid { + req := &dto.OutfitGenerateReq{ + StartDate: "2026-08-01", EndDate: "2026-08-02", + Location: "上海", Occasion: v, + } + if err := g.Validator().Data(req).Run(context.Background()); err != nil { + t.Fatalf("occasion %q 应通过校验: %v", v, err) + } + } + req := &dto.OutfitGenerateReq{ + StartDate: "2026-08-01", EndDate: "2026-08-02", + Location: "上海", Occasion: "随便", + } + if err := g.Validator().Data(req).Run(context.Background()); err == nil { + t.Fatal("非法 occasion 应被拒绝") + } +} + +func TestNormalizeOccasion(t *testing.T) { + if got := normalizeOccasion(""); got != "通勤" { + t.Fatalf("空场景应默认通勤, got %q", got) + } + if got := normalizeOccasion("约会"); got != "约会" { + t.Fatalf("非空场景应原样返回, got %q", got) + } +}