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())
|
|||
|
|
}
|