package placement_topic import ( brandentity "haixun-backend/internal/model/brand/domain/entity" kgusecase "haixun-backend/internal/model/knowledge_graph/domain/usecase" outreachusecase "haixun-backend/internal/model/outreach_draft/domain/usecase" domusecase "haixun-backend/internal/model/placement_topic/domain/usecase" scanpostusecase "haixun-backend/internal/model/scan_post/domain/usecase" "haixun-backend/internal/types" ) func toPlacementTopicData(item domusecase.TopicSummary) types.PlacementTopicData { return types.PlacementTopicData{ ID: item.ID, BrandID: item.BrandID, BrandDisplayName: item.BrandDisplayName, TopicName: item.TopicName, SeedQuery: item.SeedQuery, Brief: item.Brief, ProductID: item.ProductID, ResearchMap: toResearchMapData(item.ResearchMap), CreateAt: item.CreateAt, UpdateAt: item.UpdateAt, } } func toListData(result *domusecase.ListResult) *types.ListPlacementTopicsData { if result == nil { return &types.ListPlacementTopicsData{List: []types.PlacementTopicData{}} } list := make([]types.PlacementTopicData, 0, len(result.List)) for _, item := range result.List { list = append(list, toPlacementTopicData(item)) } return &types.ListPlacementTopicsData{List: list} } func toResearchMapData(item brandentity.ResearchMap) types.ResearchMapData { items := make([]types.ResearchItemData, 0, len(item.ResearchItems)) for _, researchItem := range item.ResearchItems { items = append(items, types.ResearchItemData{ Title: researchItem.Title, URL: researchItem.URL, Snippet: researchItem.Snippet, Query: researchItem.Query, }) } return types.ResearchMapData{ AudienceSummary: item.AudienceSummary, ContentGoal: item.ContentGoal, Questions: item.Questions, Pillars: item.Pillars, Exclusions: item.Exclusions, ResearchItems: items, ExpandStrategy: item.ExpandStrategy, PatrolKeywords: append([]string(nil), item.PatrolKeywords...), } } func toTopicPatch(req *types.UpdatePlacementTopicReq) domusecase.TopicPatch { if req == nil { return domusecase.TopicPatch{} } patch := domusecase.TopicPatch{ BrandID: req.BrandID, TopicName: req.TopicName, SeedQuery: req.SeedQuery, Brief: req.Brief, ProductID: req.ProductID, } if req.AudienceSummary != nil { patch.AudienceSummary = req.AudienceSummary } if req.ContentGoal != nil { patch.ContentGoal = req.ContentGoal } if req.Questions != nil { patch.QuestionsSet = true patch.Questions = append([]string(nil), req.Questions...) } if req.Pillars != nil { patch.PillarsSet = true patch.Pillars = append([]string(nil), req.Pillars...) } if req.Exclusions != nil { patch.ExclusionsSet = true patch.Exclusions = append([]string(nil), req.Exclusions...) } if req.PatrolKeywords != nil { patch.PatrolKeywordsSet = true patch.PatrolKeywords = append([]string(nil), req.PatrolKeywords...) } return patch } func toKnowledgeGraphData(graph *kgusecase.GraphSummary) types.KnowledgeGraphData { if graph == nil { return types.KnowledgeGraphData{} } nodes := make([]types.KnowledgeGraphNodeData, 0, len(graph.Nodes)) for _, node := range graph.Nodes { evidence := make([]types.KnowledgeGraphEvidenceData, 0, len(node.Evidence)) for _, item := range node.Evidence { evidence = append(evidence, types.KnowledgeGraphEvidenceData{ URL: item.URL, Snippet: item.Snippet, Query: item.Query, }) } nodes = append(nodes, types.KnowledgeGraphNodeData{ ID: node.ID, Label: node.Label, NodeKind: node.NodeKind, Type: node.Type, Layer: node.Layer, Relation: node.Relation, PlacementValue: node.PlacementValue, ProductFitScore: node.ProductFitScore, SelectedForScan: node.SelectedForScan, RelevanceTags: append([]string{}, node.DerivedTags.Relevance...), RecencyTags: append([]string{}, node.DerivedTags.Recency...), Evidence: evidence, }) } edges := make([]types.KnowledgeGraphEdgeData, 0, len(graph.Edges)) for _, edge := range graph.Edges { edges = append(edges, types.KnowledgeGraphEdgeData{ From: edge.From, To: edge.To, Relation: edge.Relation, }) } sources := make([]types.BraveSourceData, 0, len(graph.BraveSources)) for _, src := range graph.BraveSources { sources = append(sources, types.BraveSourceData{ Query: src.Query, Title: src.Title, URL: src.URL, Snippet: src.Snippet, }) } return types.KnowledgeGraphData{ ID: graph.ID, BrandID: graph.BrandID, Seed: graph.Seed, Nodes: nodes, Edges: edges, BraveSources: sources, ExpandStrategy: graph.ExpandStrategy, PainTagCount: graph.PainTagCount, GeneratedAt: graph.GeneratedAt, CreateAt: graph.CreateAt, UpdateAt: graph.UpdateAt, } } func toScanPostData(post *scanpostusecase.ScanPostSummary) *types.ScanPostData { if post == nil { return nil } return &types.ScanPostData{ ID: post.ID, GraphNodeID: post.GraphNodeID, SearchTag: post.SearchTag, QueryDimension: post.QueryDimension, ExternalID: post.ExternalID, Permalink: post.Permalink, Author: post.Author, Text: post.Text, Priority: post.Priority, PlacementScore: post.PlacementScore, ProductFitScore: post.ProductFitScore, SolvedByProduct: post.SolvedByProduct, Source: post.Source, ScanJobID: post.ScanJobID, OutreachStatus: post.OutreachStatus, PublishedReplyID: post.PublishedReplyID, PublishedPermalink: post.PublishedPermalink, OutreachUpdateAt: post.OutreachUpdateAt, PostedAt: post.PostedAt, Replies: toScanReplyData(post.Replies), CreateAt: post.CreateAt, } } func toScanReplyData(replies []scanpostusecase.ScanReplySummary) []types.ScanReplyData { if len(replies) == 0 { return nil } out := make([]types.ScanReplyData, 0, len(replies)) for _, reply := range replies { out = append(out, types.ScanReplyData{ ExternalID: reply.ExternalID, Author: reply.Author, Text: reply.Text, Permalink: reply.Permalink, LikeCount: reply.LikeCount, PostedAt: reply.PostedAt, }) } return out } func toOutreachDraftData(saved *outreachusecase.DraftSummary) *types.GenerateOutreachDraftsData { if saved == nil { return nil } drafts := make([]types.OutreachDraftItemData, 0, len(saved.Drafts)) for _, item := range saved.Drafts { drafts = append(drafts, types.OutreachDraftItemData{ Text: item.Text, Angle: item.Angle, Rationale: item.Rationale, }) } return &types.GenerateOutreachDraftsData{ ID: saved.ID, ScanPostID: saved.ScanPostID, Relevance: saved.Relevance, Reason: saved.Reason, Drafts: drafts, CreateAt: saved.CreateAt, } }