thread-master/apps/backend/internal/logic/insightsapi/get_insights_summary_logic.go

124 lines
3.7 KiB
Go
Raw Permalink Normal View History

2026-07-23 05:56:42 +00:00
package insightsapi
import (
"context"
"fmt"
"sort"
"time"
"apps/backend/internal/middleware"
"apps/backend/internal/module/growth/usecase"
"apps/backend/internal/svc"
"apps/backend/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type GetInsightsSummaryLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewGetInsightsSummaryLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetInsightsSummaryLogic {
return &GetInsightsSummaryLogic{Logger: logx.WithContext(ctx), ctx: ctx, svcCtx: svcCtx}
}
func (l *GetInsightsSummaryLogic) GetInsightsSummary(req *types.InsightsSummaryReq) (*types.InsightsSummaryData, error) {
uid, ok := middleware.UIDFrom(l.ctx)
if !ok || uid <= 0 {
return nil, fmt.Errorf("unauthorized")
}
if l.svcCtx.Studio == nil {
return &types.InsightsSummaryData{Conclusion: "尚無創作資料", Suggestions: []string{"先同步已發貼文"}}, nil
}
posts, err := l.svcCtx.Studio.ListOwnPosts(l.ctx, uid, req.AccountId)
if err != nil {
return nil, err
}
months := req.Months
if months <= 0 {
months = 3
}
cutoff := time.Now().UTC().AddDate(0, -months, 0).UnixNano()
type agg struct{ posts, views, likes, replies int }
byMonth := map[string]*agg{}
var totalV, totalL, totalR, n int
var top []types.InsightsPostPublic
for _, p := range posts {
if p == nil {
continue
}
ts := p.PublishedAt
if ts > 0 && ts < cutoff {
continue
}
n++
totalV += p.ViewCount
totalL += p.LikeCount
totalR += p.ReplyCount
mk := time.Unix(0, ts).UTC().Format("2006-01")
if ts == 0 {
mk = time.Now().UTC().Format("2006-01")
}
a := byMonth[mk]
if a == nil {
a = &agg{}
byMonth[mk] = a
}
a.posts++
a.views += p.ViewCount
a.likes += p.LikeCount
a.replies += p.ReplyCount
eng := 0.0
if p.ViewCount > 0 {
eng = float64(p.LikeCount+p.ReplyCount) / float64(p.ViewCount)
}
prev := p.Text
if len([]rune(prev)) > 80 {
prev = string([]rune(prev)[:80]) + "…"
}
top = append(top, types.InsightsPostPublic{
Id: p.ID, TextPreview: prev, PublishedAt: ts,
2026-07-30 01:25:34 +00:00
ViewCount: p.ViewCount, LikeCount: p.LikeCount, ReplyCount: p.ReplyCount, EngRate: usecase.RoundRate(eng),
2026-07-23 05:56:42 +00:00
})
}
sort.Slice(top, func(i, j int) bool { return top[i].EngRate > top[j].EngRate })
if len(top) > 5 {
top = top[:5]
}
avgEng := 0.0
if totalV > 0 {
avgEng = float64(totalL+totalR) / float64(totalV)
}
var buckets []types.InsightsMonthBucket
for mk, a := range byMonth {
e := 0.0
if a.views > 0 {
e = float64(a.likes+a.replies) / float64(a.views)
}
buckets = append(buckets, types.InsightsMonthBucket{
2026-07-30 01:25:34 +00:00
MonthKey: mk, Posts: a.posts, Views: a.views, Likes: a.likes, Replies: a.replies, AvgEngRate: usecase.RoundRate(e),
2026-07-23 05:56:42 +00:00
})
}
sort.Slice(buckets, func(i, j int) bool { return buckets[i].MonthKey < buckets[j].MonthKey })
conclusion := fmt.Sprintf("近 %d 個月同步貼文 %d 則,平均互動率 %.2f%%。", months, n, avgEng*100)
sugs := []string{"維持高互動題材節奏", "把表現佳貼文結構拿去仿寫"}
if n == 0 {
conclusion = "尚無足夠已同步貼文"
sugs = []string{"到創作 → 我的貼文按同步", "連好 Threads 帳號後再看成效"}
} else if avgEng < 0.02 {
sugs = append([]string{"互動率偏低:可加強開頭鉤子與提問 CTA"}, sugs...)
}
// also feed benchmark
if n > 0 {
_ = l.svcCtx.Growth.ContributeBenchmark(l.ctx, uid, "general", avgEng, float64(totalV)/float64(n))
}
return &types.InsightsSummaryData{
AccountId: req.AccountId, PostCount: n, TotalViews: totalV, TotalLikes: totalL, TotalReplies: totalR,
2026-07-30 01:25:34 +00:00
AvgEngRate: usecase.RoundRate(avgEng), TopPosts: top, MonthBuckets: buckets,
2026-07-23 05:56:42 +00:00
Conclusion: conclusion, Suggestions: sugs,
}, nil
}