thread-master/internal/library/placement/context_prompt.go

152 lines
4.5 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 placement
import (
"strings"
branddomain "haixun-backend/internal/model/brand/domain/usecase"
topicdomain "haixun-backend/internal/model/placement_topic/domain/usecase"
)
// PlacementTopicContext bundles brand, product, and user-entered topic fields for prompts.
type PlacementTopicContext struct {
BrandDisplayName string
TopicName string
SeedQuery string
Brief string
Goals string
TargetAudience string
ProductContext string
ProductBrief string
ProductLabel string
}
func PlacementTopicContextFromTopic(topic *topicdomain.TopicSummary, brand *branddomain.BrandSummary, productBrief string) PlacementTopicContext {
if topic == nil {
return PlacementTopicContextFromBrand(brand, productBrief)
}
merged := brandSummaryForTopic(topic, brand)
return PlacementTopicContextFromBrand(merged, productBrief)
}
func brandSummaryForTopic(topic *topicdomain.TopicSummary, brand *branddomain.BrandSummary) *branddomain.BrandSummary {
if brand == nil {
return nil
}
out := *brand
out.TopicName = strings.TrimSpace(topic.TopicName)
out.SeedQuery = strings.TrimSpace(topic.SeedQuery)
out.Brief = strings.TrimSpace(topic.Brief)
out.ProductID = strings.TrimSpace(topic.ProductID)
out.ResearchMap = topic.ResearchMap
return &out
}
func PlacementTopicContextFromBrand(brand *branddomain.BrandSummary, productBrief string) PlacementTopicContext {
if brand == nil {
return PlacementTopicContext{}
}
ctx := PlacementTopicContext{
BrandDisplayName: strings.TrimSpace(brand.DisplayName),
TopicName: strings.TrimSpace(brand.TopicName),
SeedQuery: strings.TrimSpace(brand.SeedQuery),
Brief: strings.TrimSpace(brand.Brief),
Goals: strings.TrimSpace(brand.Goals),
TargetAudience: strings.TrimSpace(brand.TargetAudience),
ProductContext: strings.TrimSpace(brand.ProductContext),
ProductBrief: strings.TrimSpace(productBrief),
ProductLabel: productLabelFromBrand(brand),
}
if ctx.ProductBrief == "" {
ctx.ProductBrief = strings.TrimSpace(brand.ProductBrief)
}
return ctx
}
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 {
return strings.TrimSpace(item.Label)
}
}
return ""
}
func (c PlacementTopicContext) ToResearchMapInput() ResearchMapInput {
return ResearchMapInput{
BrandDisplayName: c.BrandDisplayName,
TopicName: c.TopicName,
SeedQuery: c.SeedQuery,
Brief: c.Brief,
Goals: c.Goals,
TargetAudience: c.TargetAudience,
ProductContext: c.ProductContext,
ProductBrief: c.ProductBrief,
ProductLabel: c.ProductLabel,
}
}
func (c PlacementTopicContext) WritePromptBlock(b *strings.Builder) {
writePromptSection(b, "品牌", c.BrandDisplayName)
writePromptSection(b, "置入產品", c.ProductDisplayName())
writePromptSection(b, "主題名稱", c.TopicName)
writePromptSection(b, "種子關鍵字", c.SeedQuery)
writePromptSection(b, "主題目標", c.Brief)
writePromptSection(b, "置入目標/備註", c.Goals)
writePromptSection(b, "已知受眾描述", c.TargetAudience)
productDetail := FormatProductContextForPrompt(c.ProductContext)
if productDetail == "" && c.ProductBrief != "" {
productDetail = c.ProductBrief
}
if productDetail != "" {
b.WriteString("【產品詳情】\n")
b.WriteString(productDetail)
b.WriteString("\n")
}
}
func (c PlacementTopicContext) ProductDisplayName() string {
fields := ParseProductContext(c.ProductContext)
if fields.Product != "" {
return fields.Product
}
return c.ProductLabel
}
func writePromptSection(b *strings.Builder, label, value string) {
value = strings.TrimSpace(value)
if value == "" {
return
}
b.WriteString("【")
b.WriteString(label)
b.WriteString("】")
b.WriteString(value)
b.WriteString("\n")
}
// PromptLines returns optional labeled lines for knowledge graph template vars.
func (c PlacementTopicContext) PromptLines() map[string]string {
productName := c.ProductDisplayName()
return map[string]string{
"brand_line": optionalPromptLine("品牌", c.BrandDisplayName),
"topic_line": optionalPromptLine("主題名稱", c.TopicName),
"product_line": optionalPromptLine("置入產品", productName),
"goals_line": optionalPromptLine("置入目標", c.Goals),
}
}
func optionalPromptLine(label, value string) string {
value = strings.TrimSpace(value)
if value == "" {
return ""
}
return label + "" + value + "\n"
}