102 lines
3.0 KiB
Go
102 lines
3.0 KiB
Go
package viral
|
||
|
||
import (
|
||
"encoding/json"
|
||
"fmt"
|
||
"strings"
|
||
)
|
||
|
||
type ViralAnalysis struct {
|
||
HookPattern string `json:"hookPattern"`
|
||
StructurePattern string `json:"structurePattern"`
|
||
EmotionalTrigger string `json:"emotionalTrigger"`
|
||
ReplicationStrategy string `json:"replicationStrategy"`
|
||
KeyTakeaways []string `json:"keyTakeaways"`
|
||
}
|
||
|
||
type AnalyzeViralInput struct {
|
||
PostText string
|
||
AuthorName string
|
||
LikeCount int
|
||
ReplyCount int
|
||
SearchTag string
|
||
TopicLabel string
|
||
TopicBrief string
|
||
Persona string
|
||
}
|
||
|
||
func BuildAnalyzeViralSystemPrompt() string {
|
||
return strings.TrimSpace(`你是 Threads 爆款結構分析師。拆解貼文為什麼會紅、怎麼仿寫結構,不要建議抄襲原文。
|
||
|
||
只回傳 JSON:hookPattern, structurePattern, emotionalTrigger, replicationStrategy, keyTakeaways(字串陣列 3~5 項)。繁體中文。`)
|
||
}
|
||
|
||
func BuildAnalyzeViralUserPrompt(in AnalyzeViralInput) string {
|
||
var b strings.Builder
|
||
b.WriteString("主題:")
|
||
b.WriteString(strings.TrimSpace(in.TopicLabel))
|
||
b.WriteString("\n")
|
||
if brief := strings.TrimSpace(in.TopicBrief); brief != "" {
|
||
b.WriteString("Brief:")
|
||
b.WriteString(brief)
|
||
b.WriteString("\n")
|
||
}
|
||
if tag := strings.TrimSpace(in.SearchTag); tag != "" {
|
||
b.WriteString("搜尋標籤:")
|
||
b.WriteString(tag)
|
||
b.WriteString("\n")
|
||
}
|
||
author := strings.TrimSpace(in.AuthorName)
|
||
if author == "" {
|
||
author = "匿名"
|
||
}
|
||
b.WriteString(fmt.Sprintf("\n作者 @%s · %d 讚 · %d 留言\n", author, in.LikeCount, in.ReplyCount))
|
||
b.WriteString("\n貼文:\n")
|
||
b.WriteString(strings.TrimSpace(in.PostText))
|
||
return b.String()
|
||
}
|
||
|
||
func ParseAnalyzeViralOutput(raw string) (ViralAnalysis, error) {
|
||
payload, err := extractCopyMapJSON(raw)
|
||
if err != nil {
|
||
return ViralAnalysis{}, err
|
||
}
|
||
var out ViralAnalysis
|
||
if err := json.Unmarshal(payload, &out); err != nil {
|
||
return ViralAnalysis{}, fmt.Errorf("parse viral analysis: %w", err)
|
||
}
|
||
if strings.TrimSpace(out.HookPattern) == "" && strings.TrimSpace(out.StructurePattern) == "" {
|
||
return ViralAnalysis{}, fmt.Errorf("viral analysis missing content")
|
||
}
|
||
return out, nil
|
||
}
|
||
|
||
func FormatAnalysisForReplicate(analysis ViralAnalysis) string {
|
||
var b strings.Builder
|
||
if hook := strings.TrimSpace(analysis.HookPattern); hook != "" {
|
||
b.WriteString("Hook 模式:")
|
||
b.WriteString(hook)
|
||
b.WriteString("\n")
|
||
}
|
||
if structure := strings.TrimSpace(analysis.StructurePattern); structure != "" {
|
||
b.WriteString("結構節奏:")
|
||
b.WriteString(structure)
|
||
b.WriteString("\n")
|
||
}
|
||
if emotion := strings.TrimSpace(analysis.EmotionalTrigger); emotion != "" {
|
||
b.WriteString("情緒觸發:")
|
||
b.WriteString(emotion)
|
||
b.WriteString("\n")
|
||
}
|
||
if strategy := strings.TrimSpace(analysis.ReplicationStrategy); strategy != "" {
|
||
b.WriteString("仿寫策略:")
|
||
b.WriteString(strategy)
|
||
b.WriteString("\n")
|
||
}
|
||
if len(analysis.KeyTakeaways) > 0 {
|
||
b.WriteString("重點:")
|
||
b.WriteString(strings.Join(analysis.KeyTakeaways, ";"))
|
||
}
|
||
return strings.TrimSpace(b.String())
|
||
}
|