Merge branch 'feat-cjy-report-new' into dev

This commit is contained in:
cjy 2026-03-03 09:18:04 +08:00
commit 916fcb398e
2 changed files with 112 additions and 11 deletions

View File

@ -100,21 +100,21 @@ type DataPerformanceData struct {
// CompetitorReportResponse 竞品报告响应数据
type CompetitorReportResponse struct {
ImageURL string `json:"image_url,omitempty"` // 生成的图片URL1024*1024非必须返回
Text string `json:"text,omitempty"` // 竞品报告文本内容,非必须返回
JsonData *CompetitorReportData `json:"json_data,omitempty"` // 竞品报告JSON数据
ImageURL string `json:"image_url,omitempty"` // 生成的图片URL1024*1024非必须返回
Text string `json:"text,omitempty"` // 竞品报告文本内容,非必须返回
JsonData *CompetitorReportData `json:"json_data,omitempty"` // 竞品报告JSON数据
}
// CompetitorReportJSON AI返回的JSON结构
type CompetitorReportJSON struct {
HighlightAnalysis HighlightAnalysis `json:"highlight_analysis"`
DataPerformance DataPerformance `json:"data_performance_analysis"`
OverallSummary string `json:"overall_summary_and_optimization"`
DataPerformance DataPerformance `json:"data_performance_analysis"`
OverallSummary string `json:"overall_summary_and_optimization"`
}
type HighlightAnalysis struct {
Summary string `json:"summary"`
Points Points `json:"points"`
Summary string `json:"summary"`
Points Points `json:"points"`
}
type Points struct {
@ -127,9 +127,9 @@ type Points struct {
}
type DataPerformance struct {
Views string `json:"views"`
Completion string `json:"completion_rate,omitempty"`
Engagement string `json:"engagement"`
Views string `json:"views"`
Completion string `json:"completion_rate,omitempty"`
Engagement string `json:"engagement"`
}
// convertJSONToText 将 JSON 转换为纯文本格式
@ -321,9 +321,14 @@ func AICompetitorReport(ctx *gin.Context) {
isVideo := len(req.Videos) > 0
// 构建文本生成提示词:理解内容 + 用户要求JSON格式
// 重要必须明确要求使用英文标点符号确保返回的JSON符合规范
// 重要:必须基于内容给出分析性回复,即使没有提供具体数据
var textPrompt string
if isVideo {
textPrompt = fmt.Sprintf(`你必须严格输出以下JSON格式不要输出任何其他内容输出必须以 { 开头并以 } 结束
重要提示
1. 所有字符串值必须使用英文标点符号包括英文逗号, 英文句号. 英文冒号: 英文引号" 禁止使用中文标点符号
2. 即使没有提供具体数据也要基于视频和图片内容给出分析性回复禁止回复"未提供数据""暂无数据"等类似内容而应该根据内容分析数据表现如根据时长分析完播率潜力根据内容质量分析互动潜力等
基于以下视频和图片的内容描述
%s
@ -334,7 +339,10 @@ func AICompetitorReport(ctx *gin.Context) {
JSON结构是固定的请将内容填充到对应的value中禁止修改key禁止添加额外字段禁止输出任何说明文字
{"highlight_analysis":{"summary":"[78字以内的概述]","points":{"theme":"[标题亮点最多60字]","narrative":"[题材亮点最多60字]","content":"[内容亮点最多60字]","copywriting":"[文案亮点最多60字]","data":"[数据亮点最多60字]","music":"[配乐亮点仅视频最多60字]"}},"data_performance_analysis":{"views":"[浏览量表现最多60字]","completion_rate":"[完播率表现仅视频最多60字]","engagement":"[点赞/分享/评论表现最多60字]"},"overall_summary_and_optimization":"[整体总结及可优化建议最多300字]"}`, vlContent, req.TextPrompt)
} else {
textPrompt = fmt.Sprintf(`你必须严格输出以下JSON格式不要输出任何其他内容输出必须以 { 开头并以 } 结束
textPrompt = fmt.Sprintf(`你必须严格输出以下JSON格式不要输出任何其他内容输出开头并以 }必须以 { 结束
重要提示
1. 所有字符串值必须使用英文标点符号包括英文逗号, 英文句号. 英文冒号: 英文引号" 禁止使用中文标点符号
2. 即使没有提供具体数据也要基于视频和图片内容给出分析性回复禁止回复"未提供数据""暂无数据"等类似内容而应该根据内容分析数据表现如根据内容质量分析互动潜力等
基于以下视频和图片的内容描述
%s

View File

@ -10,9 +10,11 @@ import (
"fonchain-fiee/api/bundle"
"fonchain-fiee/api/cast"
"fonchain-fiee/pkg/cache"
"fonchain-fiee/pkg/common/qwen"
"fonchain-fiee/pkg/e"
modelCast "fonchain-fiee/pkg/model/cast"
"fonchain-fiee/pkg/model/login"
modelQwen "fonchain-fiee/pkg/model/qwen"
"fonchain-fiee/pkg/service"
"fonchain-fiee/pkg/service/bundle/common"
"fonchain-fiee/pkg/utils"
@ -607,10 +609,101 @@ func ArtistMetricsSeries(ctx *gin.Context) {
respMap["videoCount"] = videoCount
respMap["imageCount"] = imageCount
// 调用 AI 分析数据
analysis, err := generateArtistMetricsAnalysis(resp)
if err != nil {
zap.L().Error("生成艺人指标分析失败", zap.Error(err))
// AI 分析失败不影响主业务,返回空字符串
respMap["analysis"] = ""
} else {
respMap["analysis"] = analysis
}
service.Success(ctx, respMap)
return
}
// generateArtistMetricsAnalysis 调用 AI 分析艺人指标数据
func generateArtistMetricsAnalysis(resp *cast.ArtistMetricsSeriesResp) (string, error) {
if resp == nil {
return "", errors.New("数据为空")
}
// 构建分析用的数据摘要
var dataSummary strings.Builder
dataSummary.WriteString("艺人各平台数据表现如下:\n")
// 粉丝数
if resp.FansSeries != nil {
dataSummary.WriteString(fmt.Sprintf("粉丝数总数: %d (周期类型: %d, 开始日期: %d, 结束日期: %d)\n",
resp.FansSeries.FansCount, resp.FansSeries.PeriodType, resp.FansSeries.StartDate, resp.FansSeries.EndDate))
}
// 播放量
if resp.ViewsSeries != nil {
dataSummary.WriteString(fmt.Sprintf("播放量总数: %d (周期类型: %d, 开始日期: %d, 结束日期: %d)\n",
resp.ViewsSeries.ViewsCount, resp.ViewsSeries.PeriodType, resp.ViewsSeries.StartDate, resp.ViewsSeries.EndDate))
}
// 点赞数
if resp.LikesSeries != nil {
dataSummary.WriteString(fmt.Sprintf("点赞数总数: %d (周期类型: %d, 开始日期: %d, 结束日期: %d)\n",
resp.LikesSeries.LikesCount, resp.LikesSeries.PeriodType, resp.LikesSeries.StartDate, resp.LikesSeries.EndDate))
}
// 评论数
if resp.CommentsSeries != nil {
dataSummary.WriteString(fmt.Sprintf("评论数总数: %d (周期类型: %d, 开始日期: %d, 结束日期: %d)\n",
resp.CommentsSeries.CommentsCount, resp.CommentsSeries.PeriodType, resp.CommentsSeries.StartDate, resp.CommentsSeries.EndDate))
}
// 分享数
if resp.SharesSeries != nil {
dataSummary.WriteString(fmt.Sprintf("分享数总数: %d (周期类型: %d, 开始日期: %d, 结束日期: %d)\n",
resp.SharesSeries.SharesCount, resp.SharesSeries.PeriodType, resp.SharesSeries.StartDate, resp.SharesSeries.EndDate))
}
// 最佳发布时间
if resp.BestPostTime != nil {
dataSummary.WriteString(fmt.Sprintf("最佳发布时间: %s\n", resp.BestPostTime.DetailJSON))
}
// 最活跃日期
if resp.MostActiveDay != nil {
dataSummary.WriteString(fmt.Sprintf("最活跃日期: %s\n", resp.MostActiveDay.DetailJSON))
}
// 构建 prompt
prompt := fmt.Sprintf(`根据以下艺人各平台运营数据分析运营的各平台数据表现结合相关数据简要表述优点字数在200字内\n%s`, dataSummary.String())
// 调用 AI
req := modelQwen.ChatRequest{
Model: "qwen-plus",
Messages: []modelQwen.Message{
{
Role: "user",
Content: []modelQwen.Content{
{
Type: "text",
Text: prompt,
},
},
},
},
}
respAI, err := qwen.Chat(req)
if err != nil {
return "", err
}
if respAI == nil || len(respAI.Choices) == 0 {
return "", errors.New("AI 返回结果为空")
}
return respAI.Choices[0].Message.Content, nil
}
// ArtistMetricsDailyWindow 艺人指标日窗口
func ArtistMetricsDailyWindow(ctx *gin.Context) {
var req *cast.ArtistMetricsDailyWindowReq