thread-master/backend/internal/library/knowledge/patrol_input.go

149 lines
3.7 KiB
Go
Raw Permalink 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 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 ""
}