package viral import ( "context" "strings" "time" "haixun-backend/internal/library/placement" "haixun-backend/internal/library/websearch" ) const maxInspireTrendSnippets = 14 func CollectMissionInspireTrends( ctx context.Context, client websearch.Client, member placement.MemberContext, personaBrief, styleBenchmark string, ) []MissionInspireTrendSnippet { if client == nil || !client.Enabled() { return nil } queries := InspireTrendSearchQueries(personaBrief, styleBenchmark) out := make([]MissionInspireTrendSnippet, 0, maxInspireTrendSnippets) seen := map[string]struct{}{} for _, query := range queries { if len(out) >= maxInspireTrendSnippets { break } res, err := client.Search(ctx, websearch.SearchOptions{ Query: query, Limit: 5, Mode: websearch.ModeKnowledgeExpand, Country: member.BraveCountry, SearchLang: member.BraveSearchLang, UserLocation: member.ExaUserLocation, StartPublishedDate: placement.FormatPublishedAfterISO(7, time.Now().UTC()), }) if err != nil || res.Status != "success" || len(res.Results) == 0 { continue } for _, item := range res.Results { if len(out) >= maxInspireTrendSnippets { break } title := strings.TrimSpace(item.Title) snippet := strings.TrimSpace(item.Snippet) if title == "" && snippet == "" { continue } if looksLikeNewsResult(title, snippet, item.URL) { continue } key := strings.ToLower(title + "|" + snippet) if _, ok := seen[key]; ok { continue } seen[key] = struct{}{} out = append(out, MissionInspireTrendSnippet{ Query: query, Title: title, Snippet: snippet, URL: strings.TrimSpace(item.URL), }) } } return out } func looksLikeNewsResult(title, snippet, url string) bool { text := strings.ToLower(title + " " + snippet + " " + url) newsSignals := []string{"新聞", "快訊", "中央社", "聯合新聞", "ettoday", "tvbs", "setn", "ctwant", "chinatimes", "ltn.com", "news"} socialSignals := []string{"threads", "dcard", "ptt", "請問", "心得", "推薦", "有人", "怎麼辦", "討論", "留言"} newsScore := 0 for _, signal := range newsSignals { if strings.Contains(text, strings.ToLower(signal)) { newsScore++ } } if newsScore == 0 { return false } for _, signal := range socialSignals { if strings.Contains(text, strings.ToLower(signal)) { return false } } return true }