haixunMaster/haixun-backend/internal/library/knowledge/patrol_input.go

149 lines
3.7 KiB
Go
Raw Normal View History

2026-06-24 16:48:56 +00:00
package knowledge
import (
"encoding/json"
"strings"
branddomain "haixun-backend/internal/model/brand/domain/usecase"
)
// PatrolTagInput grounds海巡 tag in研究地圖與品牌產品輸入。
type PatrolTagInput struct {
BrandName string
ProductName string
ProductFeatures string
AudienceSummary string
MatchTags []string
Questions []string
Pillars []string
PatrolKeywords []string
}
type productContextFields struct {
Brand string `json:"brand"`
Product string `json:"product"`
Features string `json:"features"`
}
func parseProductContextFields(raw string) productContextFields {
raw = strings.TrimSpace(raw)
if raw == "" {
return productContextFields{}
}
var parsed productContextFields
if err := json.Unmarshal([]byte(raw), &parsed); err != nil {
return productContextFields{Features: raw}
}
parsed.Brand = strings.TrimSpace(parsed.Brand)
parsed.Product = strings.TrimSpace(parsed.Product)
parsed.Features = strings.TrimSpace(parsed.Features)
return parsed
}
func PatrolTagInputFromBrand(brand *branddomain.BrandSummary, productBrief string) PatrolTagInput {
if brand == nil {
return PatrolTagInput{}
}
fields := parseProductContextFields(brand.ProductContext)
productName := productLabelFromBrand(brand)
if productName == "" {
productName = fields.Product
}
brandName := strings.TrimSpace(brand.DisplayName)
if brandName == "" {
brandName = fields.Brand
}
features := fields.Features
if features == "" {
features = strings.TrimSpace(productBrief)
}
if features == "" {
features = strings.TrimSpace(brand.ProductBrief)
}
return PatrolTagInput{
BrandName: brandName,
ProductName: productName,
ProductFeatures: features,
AudienceSummary: strings.TrimSpace(brand.ResearchMap.AudienceSummary),
MatchTags: matchTagsFromBrand(brand),
Questions: append([]string{}, brand.ResearchMap.Questions...),
Pillars: append([]string{}, brand.ResearchMap.Pillars...),
PatrolKeywords: append([]string{}, brand.ResearchMap.PatrolKeywords...),
}
}
func productLabelFromBrand(brand *branddomain.BrandSummary) string {
if brand == nil {
return ""
}
productID := strings.TrimSpace(brand.ProductID)
if productID == "" {
return ""
}
for _, item := range brand.Products {
if item.ID == productID {
label := strings.TrimSpace(item.Label)
if label != "" {
return label
}
return parseProductContextFields(item.ProductContext).Product
}
}
return ""
}
func matchTagsFromBrand(brand *branddomain.BrandSummary) []string {
if brand == nil {
return nil
}
productID := strings.TrimSpace(brand.ProductID)
seen := map[string]struct{}{}
out := []string{}
add := func(tag string) {
tag = strings.TrimSpace(tag)
if tag == "" {
return
}
if _, ok := seen[tag]; ok {
return
}
seen[tag] = struct{}{}
out = append(out, tag)
}
for _, item := range brand.Products {
if productID != "" && item.ID != productID {
continue
}
for _, tag := range item.MatchTags {
add(tag)
}
if productID != "" {
break
}
}
return out
}
func (in PatrolTagInput) HasResearchMap() bool {
return len(in.Questions) > 0 || len(in.Pillars) > 0 || strings.TrimSpace(in.AudienceSummary) != ""
}
func (in PatrolTagInput) HasProductContext() bool {
return strings.TrimSpace(in.ProductName) != "" ||
strings.TrimSpace(in.ProductFeatures) != "" ||
len(in.MatchTags) > 0
}
func productCategoryHint(productName, features string) string {
combined := productName + " " + features
for _, hint := range []string{
"沐浴乳", "沐浴露", "洗髮精", "洗髮乳", "洗面乳", "洗面奶", "乳液", "精華",
"防曬", "卸妝", "潔面", "身體乳", "洗手乳", "清潔",
} {
if strings.Contains(combined, hint) {
return hint
}
}
return ""
}