feat: 生成接口支持场景(occasion,默认通勤,评分/LLM 依据)

This commit is contained in:
2026-07-31 17:08:40 +08:00
parent 76100a7131
commit 878468cd6d
3 changed files with 51 additions and 3 deletions
@@ -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 {
@@ -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 {
@@ -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)
}
}