thread-master/backend/internal/library/placement/product_context.go

110 lines
3.0 KiB
Go
Raw Normal View History

2026-06-26 08:37:04 +00:00
package placement
import (
"encoding/json"
"strings"
)
type CtaType string
const (
CtaNone CtaType = "none"
CtaLink CtaType = "link"
CtaDM CtaType = "dm"
CtaFollow CtaType = "follow"
)
type ProductContextFields struct {
Brand string `json:"brand"`
Product string `json:"product"`
Features string `json:"features"`
PlacementTone string `json:"placementTone,omitempty"`
CtaType CtaType `json:"ctaType,omitempty"`
CtaUrl string `json:"ctaUrl,omitempty"`
}
func ParseProductContext(raw string) ProductContextFields {
raw = strings.TrimSpace(raw)
if raw == "" {
return ProductContextFields{CtaType: CtaNone}
}
var parsed ProductContextFields
if err := json.Unmarshal([]byte(raw), &parsed); err != nil {
return ProductContextFields{CtaType: CtaNone, Features: raw}
}
parsed.Brand = strings.TrimSpace(parsed.Brand)
parsed.Product = strings.TrimSpace(parsed.Product)
parsed.Features = strings.TrimSpace(parsed.Features)
parsed.PlacementTone = strings.TrimSpace(parsed.PlacementTone)
parsed.CtaUrl = strings.TrimSpace(parsed.CtaUrl)
if parsed.CtaType == "" {
parsed.CtaType = CtaNone
}
return parsed
}
func SerializeProductContext(fields ProductContextFields) string {
brand := strings.TrimSpace(fields.Brand)
product := strings.TrimSpace(fields.Product)
features := strings.TrimSpace(fields.Features)
tone := strings.TrimSpace(fields.PlacementTone)
ctaType := fields.CtaType
if ctaType == "" {
ctaType = CtaNone
}
ctaUrl := strings.TrimSpace(fields.CtaUrl)
if brand == "" && product == "" && features == "" && tone == "" && ctaType == CtaNone && ctaUrl == "" {
return ""
}
payload, _ := json.Marshal(ProductContextFields{
Brand: brand,
Product: product,
Features: features,
PlacementTone: tone,
CtaType: ctaType,
CtaUrl: ctaUrl,
})
return string(payload)
}
func FormatProductContextForPrompt(raw string) string {
fields := ParseProductContext(raw)
lines := []string{}
if fields.Brand != "" {
lines = append(lines, "品牌:"+fields.Brand)
}
if fields.Product != "" {
lines = append(lines, "產品:"+fields.Product)
}
if fields.Features != "" {
lines = append(lines, "特色/能幫上忙的地方:"+fields.Features)
}
if fields.PlacementTone != "" {
lines = append(lines, "置入語氣偏好:"+fields.PlacementTone)
}
if fields.CtaType == CtaLink && fields.CtaUrl != "" {
lines = append(lines, "留言 CTA 連結:"+fields.CtaUrl)
} else if fields.CtaType == CtaDM {
lines = append(lines, "留言 CTA引導私訊")
} else if fields.CtaType == CtaFollow {
lines = append(lines, "留言 CTA引導追蹤")
}
if len(lines) == 0 {
return ""
}
return strings.Join(lines, "\n")
}
func ProductBriefFromContext(raw string) string {
formatted := FormatProductContextForPrompt(raw)
if formatted != "" {
return formatted
}
return strings.TrimSpace(raw)
}
func HasProductContext(raw string) bool {
fields := ParseProductContext(raw)
return fields.Brand != "" || fields.Product != "" || fields.Features != ""
}