thread-master/backend/internal/library/outreach/draft_context.go

107 lines
3.3 KiB
Go
Raw 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 outreach
import (
"fmt"
"strings"
libkg "haixun-backend/internal/library/knowledge"
libplacement "haixun-backend/internal/library/placement"
brandentity "haixun-backend/internal/model/brand/domain/entity"
branddomain "haixun-backend/internal/model/brand/domain/usecase"
scanpostusecase "haixun-backend/internal/model/scan_post/domain/usecase"
)
func FindGraphNode(nodes []libkg.Node, nodeID string) *libkg.Node {
nodeID = strings.TrimSpace(nodeID)
if nodeID == "" {
return nil
}
for i := range nodes {
if nodes[i].ID == nodeID {
return &nodes[i]
}
}
return nil
}
func BuildPlacementReason(post *scanpostusecase.ScanPostSummary) string {
if post == nil {
return ""
}
parts := []string{}
if post.Priority == "gold" {
parts = append(parts, "雙軌命中(相關+近期)")
} else if post.Priority == "recent" {
parts = append(parts, "近期軌命中")
}
if post.SolvedByProduct {
parts = append(parts, "產品可解此需求")
}
if post.ProductFitScore > 0 {
parts = append(parts, fmt.Sprintf("產品匹配 %d", post.ProductFitScore))
}
return strings.Join(parts, "")
}
func MergePlacementReason(base string, node *libkg.Node, post *scanpostusecase.ScanPostSummary) string {
parts := []string{}
if strings.TrimSpace(base) != "" {
parts = append(parts, strings.TrimSpace(base))
}
if node != nil {
if strings.TrimSpace(node.PlacementValue) != "" {
parts = append(parts, "置入價值 "+strings.TrimSpace(node.PlacementValue))
}
if node.ProductFitScore > 0 && (post == nil || post.ProductFitScore == 0) {
parts = append(parts, fmt.Sprintf("節點產品匹配 %d", node.ProductFitScore))
}
}
return strings.Join(parts, "")
}
func ProductBriefForBrand(brand *branddomain.BrandSummary, productID, searchTag, postText string) string {
if brand == nil {
return ""
}
if product := PickProductForOutreach(brand, productID, searchTag, postText); product != nil {
merged := libplacement.BuildMergedProductContext(brand.DisplayName, product.ProductContext, product.Label)
merged = libplacement.ApplyPlacementURL(merged, product.PlacementURL)
if pb := libplacement.ProductBriefFromContext(merged); pb != "" {
return pb
}
}
if pb := libplacement.ProductBriefFromContext(brand.ProductContext); pb != "" {
return pb
}
return strings.TrimSpace(brand.ProductBrief)
}
func PickProductForOutreach(brand *branddomain.BrandSummary, preferredProductID, searchTag, postText string) *branddomain.ProductSummary {
if brand == nil || len(brand.Products) == 0 {
return nil
}
entities := make([]brandentity.Product, len(brand.Products))
for i := range brand.Products {
entities[i] = brandentity.Product{
ID: brand.Products[i].ID,
Label: brand.Products[i].Label,
ProductContext: brand.Products[i].ProductContext,
MatchTags: append([]string(nil), brand.Products[i].MatchTags...),
}
}
if picked := libplacement.RecommendProductForPost(entities, searchTag, postText, preferredProductID); picked != nil {
for i := range brand.Products {
if brand.Products[i].ID == picked.ID {
return &brand.Products[i]
}
}
}
if id := strings.TrimSpace(preferredProductID); id != "" {
for i := range brand.Products {
if brand.Products[i].ID == id {
return &brand.Products[i]
}
}
}
return &brand.Products[0]
}