thread-master/backend/internal/logic/copy_mission/mapper.go

300 lines
10 KiB
Go
Raw Permalink Normal View History

2026-06-26 08:37:04 +00:00
package copy_mission
import (
copydraftdomain "haixun-backend/internal/model/copy_draft/domain/usecase"
missionentity "haixun-backend/internal/model/copy_mission/domain/entity"
missiondomain "haixun-backend/internal/model/copy_mission/domain/usecase"
personadomain "haixun-backend/internal/model/persona/domain/usecase"
scanpostdomain "haixun-backend/internal/model/scan_post/domain/usecase"
"haixun-backend/internal/types"
)
func seedMissionResearchFromPersona(persona personadomain.PersonaSummary) (*missionentity.ResearchMap, []string) {
src := persona.CopyResearchMap
if src.AudienceSummary == "" && src.ContentGoal == "" && len(src.SuggestedTags) == 0 {
return nil, nil
}
tags := make([]missionentity.SuggestedTag, 0, len(src.SuggestedTags))
for _, tag := range src.SuggestedTags {
if tag == "" {
continue
}
tags = append(tags, missionentity.SuggestedTag{Tag: tag})
}
selected := append([]string(nil), src.SuggestedTags...)
if len(selected) > 6 {
selected = selected[:6]
}
rm := &missionentity.ResearchMap{
AudienceSummary: src.AudienceSummary,
ContentGoal: src.ContentGoal,
Questions: append([]string(nil), src.Questions...),
Pillars: append([]string(nil), src.Pillars...),
Exclusions: append([]string(nil), src.Exclusions...),
SuggestedTags: tags,
BenchmarkNotes: src.BenchmarkNotes,
}
return rm, selected
}
func toMissionPatch(req *types.UpdateCopyMissionReq) missiondomain.MissionPatch {
if req == nil {
return missiondomain.MissionPatch{}
}
patch := missiondomain.MissionPatch{
Label: req.Label,
SeedQuery: req.SeedQuery,
Brief: req.Brief,
}
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...)
}
2026-06-28 08:28:42 +00:00
if req.KnowledgeItems != nil {
patch.KnowledgeItemsSet = true
patch.KnowledgeItems = append([]string(nil), req.KnowledgeItems...)
}
if req.SelectedKnowledgeItems != nil {
patch.SelectedKnowledgeItemsSet = true
patch.SelectedKnowledgeItems = append([]string(nil), req.SelectedKnowledgeItems...)
}
2026-06-26 08:37:04 +00:00
if req.BenchmarkNotes != nil {
patch.BenchmarkNotes = req.BenchmarkNotes
}
if req.SelectedTags != nil {
patch.SelectedTagsSet = true
patch.SelectedTags = append([]string(nil), req.SelectedTags...)
}
return patch
}
2026-06-28 08:28:42 +00:00
func toResearchItemData(items []missiondomain.ResearchItemSummary) []types.CopyMissionResearchItemData {
out := make([]types.CopyMissionResearchItemData, 0, len(items))
for _, item := range items {
out = append(out, types.CopyMissionResearchItemData{
Title: item.Title,
URL: item.URL,
Snippet: item.Snippet,
Query: item.Query,
})
}
return out
}
2026-06-26 08:37:04 +00:00
func toCopyMissionData(item missiondomain.MissionSummary) types.CopyMissionData {
tags := make([]types.CopySuggestedTagData, 0, len(item.ResearchMap.SuggestedTags))
for _, tag := range item.ResearchMap.SuggestedTags {
tags = append(tags, types.CopySuggestedTagData{
Tag: tag.Tag,
Reason: tag.Reason,
SearchIntent: tag.SearchIntent,
SearchType: tag.SearchType,
})
}
accounts := make([]types.CopySimilarAccountData, 0, len(item.ResearchMap.SimilarAccounts))
for _, acc := range item.ResearchMap.SimilarAccounts {
accounts = append(accounts, types.CopySimilarAccountData{
Username: acc.Username,
Reason: acc.Reason,
Source: acc.Source,
2026-06-28 08:28:42 +00:00
MatchedSource: append([]string(nil), acc.MatchedSource...),
2026-06-26 08:37:04 +00:00
Confidence: acc.Confidence,
2026-06-28 08:28:42 +00:00
Status: acc.Status,
TopicRelevance: acc.TopicRelevance,
LastSeenAt: acc.LastSeenAt,
2026-06-26 08:37:04 +00:00
ProfileUrl: acc.ProfileURL,
AuthorVerified: acc.AuthorVerified,
FollowerCount: acc.FollowerCount,
EngagementScore: acc.EngagementScore,
LikeCount: acc.LikeCount,
ReplyCount: acc.ReplyCount,
PostCount: acc.PostCount,
})
}
2026-06-28 08:28:42 +00:00
samples := make([]types.CopyAudienceSampleData, 0, len(item.ResearchMap.AudienceSamples))
for _, sample := range item.ResearchMap.AudienceSamples {
samples = append(samples, types.CopyAudienceSampleData{
Username: sample.Username,
SamplePostId: sample.SamplePostID,
SampleText: sample.SampleText,
ReplyLikeCount: sample.ReplyLikeCount,
Appearances: sample.Appearances,
FirstSeenAt: sample.FirstSeenAt,
LastSeenAt: sample.LastSeenAt,
Status: sample.Status,
})
}
2026-06-26 08:37:04 +00:00
return types.CopyMissionData{
ID: item.ID,
PersonaID: item.PersonaID,
Label: item.Label,
SeedQuery: item.SeedQuery,
Brief: item.Brief,
ResearchMap: types.CopyMissionResearchMapData{
2026-06-28 08:28:42 +00:00
AudienceSummary: item.ResearchMap.AudienceSummary,
ContentGoal: item.ResearchMap.ContentGoal,
Questions: append([]string(nil), item.ResearchMap.Questions...),
Pillars: append([]string(nil), item.ResearchMap.Pillars...),
Exclusions: append([]string(nil), item.ResearchMap.Exclusions...),
KnowledgeItems: append([]string(nil), item.ResearchMap.KnowledgeItems...),
SelectedKnowledgeItems: append([]string(nil), item.ResearchMap.SelectedKnowledgeItems...),
ResearchItems: toResearchItemData(item.ResearchMap.ResearchItems),
SuggestedTags: tags,
SimilarAccounts: accounts,
AudienceSamples: samples,
BenchmarkNotes: item.ResearchMap.BenchmarkNotes,
2026-06-26 08:37:04 +00:00
},
SelectedTags: append([]string(nil), item.SelectedTags...),
LastScanJobID: item.LastScanJobID,
Status: item.Status,
CreateAt: item.CreateAt,
UpdateAt: item.UpdateAt,
}
}
func toListData(result *missiondomain.ListResult) *types.ListCopyMissionsData {
if result == nil {
return &types.ListCopyMissionsData{List: []types.CopyMissionData{}}
}
list := make([]types.CopyMissionData, 0, len(result.List))
for _, item := range result.List {
list = append(list, toCopyMissionData(item))
}
return &types.ListCopyMissionsData{List: list}
}
func toEntityResearchMap(data types.CopyMissionResearchMapData) missionentity.ResearchMap {
tags := make([]missionentity.SuggestedTag, 0, len(data.SuggestedTags))
for _, tag := range data.SuggestedTags {
tags = append(tags, missionentity.SuggestedTag{
Tag: tag.Tag,
Reason: tag.Reason,
SearchIntent: tag.SearchIntent,
SearchType: tag.SearchType,
})
}
accounts := make([]missionentity.SimilarAccount, 0, len(data.SimilarAccounts))
for _, acc := range data.SimilarAccounts {
accounts = append(accounts, missionentity.SimilarAccount{
Username: acc.Username,
Reason: acc.Reason,
Source: acc.Source,
2026-06-28 08:28:42 +00:00
MatchedSource: append([]string(nil), acc.MatchedSource...),
2026-06-26 08:37:04 +00:00
Confidence: acc.Confidence,
2026-06-28 08:28:42 +00:00
Status: acc.Status,
TopicRelevance: acc.TopicRelevance,
LastSeenAt: acc.LastSeenAt,
2026-06-26 08:37:04 +00:00
ProfileURL: acc.ProfileUrl,
AuthorVerified: acc.AuthorVerified,
FollowerCount: acc.FollowerCount,
EngagementScore: acc.EngagementScore,
LikeCount: acc.LikeCount,
ReplyCount: acc.ReplyCount,
PostCount: acc.PostCount,
})
}
2026-06-28 08:28:42 +00:00
samples := make([]missionentity.AudienceSample, 0, len(data.AudienceSamples))
for _, sample := range data.AudienceSamples {
samples = append(samples, missionentity.AudienceSample{
Username: sample.Username,
SamplePostID: sample.SamplePostId,
SampleText: sample.SampleText,
ReplyLikeCount: sample.ReplyLikeCount,
Appearances: sample.Appearances,
FirstSeenAt: sample.FirstSeenAt,
LastSeenAt: sample.LastSeenAt,
Status: sample.Status,
})
}
2026-06-26 08:37:04 +00:00
return missionentity.ResearchMap{
2026-06-28 08:28:42 +00:00
AudienceSummary: data.AudienceSummary,
ContentGoal: data.ContentGoal,
Questions: append([]string(nil), data.Questions...),
Pillars: append([]string(nil), data.Pillars...),
Exclusions: append([]string(nil), data.Exclusions...),
KnowledgeItems: append([]string(nil), data.KnowledgeItems...),
SelectedKnowledgeItems: append([]string(nil), data.SelectedKnowledgeItems...),
SuggestedTags: tags,
SimilarAccounts: accounts,
AudienceSamples: samples,
BenchmarkNotes: data.BenchmarkNotes,
2026-06-26 08:37:04 +00:00
}
}
func toViralScanPostsData(posts []scanpostdomain.ScanPostSummary) *types.ListPersonaViralScanPostsData {
list := make([]types.ViralScanPostData, 0, len(posts))
for _, post := range posts {
list = append(list, types.ViralScanPostData{
ID: post.ID,
SearchTag: post.SearchTag,
Permalink: post.Permalink,
Author: post.Author,
AuthorVerified: post.AuthorVerified,
FollowerCount: post.FollowerCount,
Text: post.Text,
LikeCount: post.LikeCount,
ReplyCount: post.ReplyCount,
EngagementScore: post.EngagementScore,
Source: post.Source,
ScanJobID: post.ScanJobID,
Replies: toScanReplyData(post.Replies),
CreateAt: post.CreateAt,
})
}
return &types.ListPersonaViralScanPostsData{List: list, Total: len(list)}
}
func toScanReplyData(replies []scanpostdomain.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 toCopyDraftData(item copydraftdomain.CopyDraftSummary) types.CopyDraftData {
return types.CopyDraftData{
ID: item.ID,
PersonaID: item.PersonaID,
CopyMissionID: item.CopyMissionID,
ScanPostID: item.ScanPostID,
DraftType: item.DraftType,
SortOrder: item.SortOrder,
Text: item.Text,
Angle: item.Angle,
Hook: item.Hook,
Rationale: item.Rationale,
ReferenceNotes: item.ReferenceNotes,
Sources: item.Sources,
Status: item.Status,
PublishedMediaID: item.PublishedMediaID,
PublishedPermalink: item.PublishedPermalink,
PublishedAt: item.PublishedAt,
CreateAt: item.CreateAt,
}
}