diff --git a/pkg/service/ai/video_vl.go b/pkg/service/ai/video_vl.go index 1a945855..8fa0eeef 100644 --- a/pkg/service/ai/video_vl.go +++ b/pkg/service/ai/video_vl.go @@ -71,11 +71,38 @@ type CompetitorReportRequest struct { Model string `json:"model"` // 可选的模型名称,默认使用 qwen3-vl-plus } +// CompetitorReportData 竞品报告数据(用于返回给前端) +type CompetitorReportData struct { + HighlightAnalysis HighlightAnalysisData `json:"highlight_analysis"` + DataPerformance DataPerformanceData `json:"data_performance_analysis"` + OverallSummary string `json:"overall_summary_and_optimization"` +} + +type HighlightAnalysisData struct { + Summary string `json:"summary"` + Points PointsData `json:"points"` +} + +type PointsData struct { + Theme string `json:"theme"` + Narrative string `json:"narrative"` + Content string `json:"content"` + Copywriting string `json:"copywriting"` + Data string `json:"data"` + Music string `json:"music,omitempty"` +} + +type DataPerformanceData struct { + Views string `json:"views"` + Completion string `json:"completion_rate,omitempty"` + Engagement string `json:"engagement"` +} + // CompetitorReportResponse 竞品报告响应数据 type CompetitorReportResponse struct { - ImageURL string `json:"image_url,omitempty"` // 生成的图片URL(1024*1024),非必须返回 - Text string `json:"text,omitempty"` // 竞品报告文本内容,非必须返回 - JSON string `json:"json,omitempty"` // 竞品报告JSON格式,非必须返回 + ImageURL string `json:"image_url,omitempty"` // 生成的图片URL(1024*1024),非必须返回 + Text string `json:"text,omitempty"` // 竞品报告文本内容,非必须返回 + JsonData *CompetitorReportData `json:"json_data,omitempty"` // 竞品报告JSON数据 } // CompetitorReportJSON AI返回的JSON结构 @@ -164,6 +191,65 @@ func convertJSONToText(data CompetitorReportJSON, isVideo bool) string { return sb.String() } +// convertJSONToTextFromData 将 JSON 转换为纯文本格式(使用新的 CompetitorReportData 结构) +func convertJSONToTextFromData(data CompetitorReportData, isVideo bool) string { + var sb strings.Builder + + // 一、亮点表现分析 + sb.WriteString("一、亮点表现分析\n") + sb.WriteString(data.HighlightAnalysis.Summary) + sb.WriteString("\n\n") + + sb.WriteString("1. 标题亮点:") + sb.WriteString(data.HighlightAnalysis.Points.Theme) + sb.WriteString("\n") + + sb.WriteString("2. 题材亮点:") + sb.WriteString(data.HighlightAnalysis.Points.Narrative) + sb.WriteString("\n") + + sb.WriteString("3. 内容亮点:") + sb.WriteString(data.HighlightAnalysis.Points.Content) + sb.WriteString("\n") + + sb.WriteString("4. 文案亮点:") + sb.WriteString(data.HighlightAnalysis.Points.Copywriting) + sb.WriteString("\n") + + sb.WriteString("5. 数据亮点:") + sb.WriteString(data.HighlightAnalysis.Points.Data) + sb.WriteString("\n") + + if isVideo && data.HighlightAnalysis.Points.Music != "" { + sb.WriteString("6. 配乐亮点:") + sb.WriteString(data.HighlightAnalysis.Points.Music) + sb.WriteString("\n") + } + + // 二、数据表现分析 + sb.WriteString("\n二、数据表现分析\n") + sb.WriteString("1. 浏览量表现:") + sb.WriteString(data.DataPerformance.Views) + sb.WriteString("\n") + + if isVideo && data.DataPerformance.Completion != "" { + sb.WriteString("2. 完播率表现:") + sb.WriteString(data.DataPerformance.Completion) + sb.WriteString("\n") + sb.WriteString("3. 点赞/分享/评论表现:") + } else { + sb.WriteString("2. 点赞/分享/评论表现:") + } + sb.WriteString(data.DataPerformance.Engagement) + sb.WriteString("\n") + + // 三、整体总结及可优化建议 + sb.WriteString("\n三、整体总结及可优化建议\n") + sb.WriteString(data.OverallSummary) + + return sb.String() +} + // AICompetitorReport 生成竞品报告接口 func AICompetitorReport(ctx *gin.Context) { var req CompetitorReportRequest @@ -387,14 +473,12 @@ JSON结构是固定的,请将内容填充到对应的value中,禁止修改ke // 返回结果(只返回实际生成的内容) result := CompetitorReportResponse{} if needText { - result.JSON = textRes.text // JSON 字段直接返回 AI 生成的 JSON - - // 将 JSON 解析并转换为纯文本 + // 将 JSON 解析为结构化数据 fmt.Println("========== 开始解析 JSON ==========") fmt.Println("原始内容是否以 { 开头:", strings.HasPrefix(strings.TrimSpace(textRes.text), "{")) fmt.Println("原始内容前100字符:", strings.TrimSpace(textRes.text)[:min(100, len(strings.TrimSpace(textRes.text)))]) - var jsonData CompetitorReportJSON + var jsonData CompetitorReportData if err := json.Unmarshal([]byte(textRes.text), &jsonData); err != nil { // 如果解析失败,回退使用原始文本 fmt.Println("========== JSON 解析失败 ==========") @@ -405,7 +489,11 @@ JSON结构是固定的,请将内容填充到对应的value中,禁止修改ke fmt.Println("========== JSON 解析成功 ==========") fmt.Println("Summary:", jsonData.HighlightAnalysis.Summary) fmt.Println("==================================") - result.Text = convertJSONToText(jsonData, len(req.Videos) > 0) + + // 赋值结构体到 JsonData 中 + result.JsonData = &jsonData + + result.Text = convertJSONToTextFromData(jsonData, len(req.Videos) > 0) } } if needImage {