From 3d112773c9639f177c49e103910eaef58e83282c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E8=82=A5=E7=BE=8A?= <1048382248@qq.com> Date: Mon, 30 Jun 2025 18:01:49 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20AI=E5=88=86=E6=9E=90?= =?UTF-8?q?=E8=A7=86=E9=A2=91=E8=AF=BE=E7=A8=8B=E7=B1=BB=E5=9E=8B=E6=B5=81?= =?UTF-8?q?=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- VideoAnalysisCore/AICore/GPT/BserGPT.cs | 6 +++ .../AICore/GPT/ChatGPT/Chat_GPT.cs | 5 ++ .../AICore/GPT/DeepSeek/DeepSeek_GPT.cs | 52 +++++++++++++++++-- .../AICore/GPT/Dto/VideoTypeDto.cs | 18 +++++++ VideoAnalysisCore/Common/RedisExpand.cs | 10 ++++ .../Controllers/ApiController.cs | 18 +++++++ VideoAnalysisCore/Job/NodePackageJob.cs | 22 ++++++-- .../Model/Enum/RedisChannelEnum.cs | 5 ++ VideoAnalysisCore/Model/NodePackageInfo.cs | 2 +- 9 files changed, 131 insertions(+), 7 deletions(-) create mode 100644 VideoAnalysisCore/AICore/GPT/Dto/VideoTypeDto.cs diff --git a/VideoAnalysisCore/AICore/GPT/BserGPT.cs b/VideoAnalysisCore/AICore/GPT/BserGPT.cs index 855fddf..9b4c914 100644 --- a/VideoAnalysisCore/AICore/GPT/BserGPT.cs +++ b/VideoAnalysisCore/AICore/GPT/BserGPT.cs @@ -22,5 +22,11 @@ namespace VideoAnalysisCore.AICore.GPT /// 任务id /// public Task GetVideoQuestion(string task); + /// + /// 获取视频类型 + /// + /// + /// + public Task GetVideoType(string task); } } diff --git a/VideoAnalysisCore/AICore/GPT/ChatGPT/Chat_GPT.cs b/VideoAnalysisCore/AICore/GPT/ChatGPT/Chat_GPT.cs index fc84ad9..47fd99e 100644 --- a/VideoAnalysisCore/AICore/GPT/ChatGPT/Chat_GPT.cs +++ b/VideoAnalysisCore/AICore/GPT/ChatGPT/Chat_GPT.cs @@ -423,5 +423,10 @@ namespace VideoAnalysisCore.AICore.GPT.ChatGPT { throw new NotImplementedException(); } + + Task IBserGPT.GetVideoType(string task) + { + throw new NotImplementedException(); + } } } diff --git a/VideoAnalysisCore/AICore/GPT/DeepSeek/DeepSeek_GPT.cs b/VideoAnalysisCore/AICore/GPT/DeepSeek/DeepSeek_GPT.cs index 4f7ce91..59391e2 100644 --- a/VideoAnalysisCore/AICore/GPT/DeepSeek/DeepSeek_GPT.cs +++ b/VideoAnalysisCore/AICore/GPT/DeepSeek/DeepSeek_GPT.cs @@ -20,6 +20,7 @@ using Aliyun.OSS; using Yitter.IdGenerator; using VideoAnalysisCore.Common.Expand; using System.Collections.Generic; +using UserCenter.Model.Enum; namespace VideoAnalysisCore.AICore.GPT.DeepSeek { @@ -346,7 +347,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek if (max_tokens != -1) chatRep.max_tokens = max_tokens; var tryCount = 10; - while (--tryCount > 0) + while (tryCount-- > 0) { try { @@ -392,8 +393,8 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek } catch (Exception ex) { - Console.WriteLine(DateTime.Now + $"=>ChatGPT结果解析错误 重试剩余{tryCount}"); Console.WriteLine(ex.Message); + Console.WriteLine(DateTime.Now + $"=>ChatGPT结果解析错误 重试剩余{tryCount}"); } } throw new Exception(DateTime.Now + "=>ChatGPT请求失败次数过多!!!"); @@ -616,7 +617,6 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek var subject = taskInfo.Subject.ToString(); var Course_Id = taskInfo.CourseId; - var captionsArr = JsonSerializer.Deserialize(taskInfo.Captions); //处理视频授课章节 var sections = await GetSections(taskInfo, Course_Id); var know = await knowledgeInfoDB.GetFirstAsync(s => s.Course_Id == Course_Id && s.Name == sections); @@ -630,5 +630,51 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek return; } + + + /// + /// 分析视频是否为复习课 + /// + /// + /// + public async Task GetVideoType(string task) + { + + var taskId = long.Parse(task); + var taskInfo = await videoTaskDB.AsQueryable() + .Where(s => s.Id == taskId) + .FirstAsync(); + + var subject = taskInfo.Subject.ToString(); + var Course_Id = taskInfo.CourseId; + var videoTypeStr = string.Join(',', Enum.GetNames(typeof(AttachmentsInfoType))); + //处理视频授课章节 + var sections = await GetSections(taskInfo, Course_Id); + + var captionsArr = JsonSerializer.Deserialize(taskInfo.Captions); + captionsArr = await OptimizeSubtitles(taskInfo, captionsArr, sections); + + //合并字幕 + var captions = ExpandFunction.GetSpeakerCaptions(captionsArr); + + var resFormat = """{ "VideoType":string(课程类型),"Reason":string(分析原因)}"""; + var postMessages = + $"我将提供一段视频的字幕内容,请你帮我分析这堂课的课程类型是什么。" + + $"授课类型限定在我提供的范围内 [{videoTypeStr}]" + + $"其中如果是[复习/习题课/试题讲解课程]那么课程类型视为'复习'" + + $"请简介的说明分析出课程类型的原因,如果分析出的课程类型与限定条件不匹配则返回NULL" + + $"输出内容只返回json格式为({resFormat})" + + $"以下是字幕内容" + + $"`{captions.Captions}`"; + var resData = await ChatAsync(taskInfo.Id.ToString(), postMessages, "视频类型", "deepseek-chat"); + var res = resData.VideoType.ToEnum(); + if (res != null) + { + await videoTaskDB.AsUpdateable() + .SetColumns(it => it.VideoType == res) + .Where(it => it.Id == taskInfo.Id) + .ExecuteCommandAsync(); + } + } } } diff --git a/VideoAnalysisCore/AICore/GPT/Dto/VideoTypeDto.cs b/VideoAnalysisCore/AICore/GPT/Dto/VideoTypeDto.cs new file mode 100644 index 0000000..458a55f --- /dev/null +++ b/VideoAnalysisCore/AICore/GPT/Dto/VideoTypeDto.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using VideoAnalysisCore.Model.Enum; + +namespace VideoAnalysisCore.AICore.GPT.Dto +{ + public class AIVideoTypeDto + { + public string? VideoType { get; set; } + /// + /// 分析结果原因 + /// + public string Reason { get; set; } + } +} diff --git a/VideoAnalysisCore/Common/RedisExpand.cs b/VideoAnalysisCore/Common/RedisExpand.cs index e883e0a..e1b18c9 100644 --- a/VideoAnalysisCore/Common/RedisExpand.cs +++ b/VideoAnalysisCore/Common/RedisExpand.cs @@ -249,6 +249,16 @@ namespace VideoAnalysisCore.Common async (msg) => await TouchChannel(RedisChannelEnum.解析字幕, msg, SenseVoice.RunTask)); //SubscribeList.Add(RedisChannelEnum.解析说话人, // async (msg) => await TouchChannel(RedisChannelEnum.解析说话人, msg, Speaker.Run)); + SubscribeList.Add(RedisChannelEnum.AI课程类型, + async (msg) => await TouchChannel(RedisChannelEnum.AI课程类型, msg, + (task) => + { + using var scope = AppCommon.Services?.CreateScope(); + if (scope is null || scope.ServiceProvider.GetService() is null) + throw new Exception("IBserGPT 未注入"); + else + return scope.ServiceProvider.GetService()?.GetVideoType(task) ?? Task.CompletedTask; + })); SubscribeList.Add(RedisChannelEnum.AI模型分析, async (msg) => await TouchChannel(RedisChannelEnum.AI模型分析, msg, (task) => diff --git a/VideoAnalysisCore/Controllers/ApiController.cs b/VideoAnalysisCore/Controllers/ApiController.cs index bbcd8ea..bb727fe 100644 --- a/VideoAnalysisCore/Controllers/ApiController.cs +++ b/VideoAnalysisCore/Controllers/ApiController.cs @@ -16,6 +16,8 @@ using Microsoft.AspNetCore.Http; using VideoAnalysisCore.Model.Dto; using VideoAnalysisCore.Controllers.Dto; using VideoAnalysisCore.Common.Expand; +using Microsoft.Extensions.DependencyInjection; +using System.Threading.Tasks; namespace VideoAnalysisCore.Controllers { @@ -68,6 +70,22 @@ namespace VideoAnalysisCore.Controllers #endif + /// + /// ʼ + /// + /// ļ + /// + [HttpGet(Name = "tets1")] + public IActionResult tets1(string task) + { + + using var scope = AppCommon.Services?.CreateScope(); + if (scope is null || scope.ServiceProvider.GetService() is null) + throw new Exception("IBserGPT δע"); + else + scope.ServiceProvider.GetService()?.GetVideoType(task); + return Ok(); + } /// /// ʶ /// diff --git a/VideoAnalysisCore/Job/NodePackageJob.cs b/VideoAnalysisCore/Job/NodePackageJob.cs index 75d96b4..badc7e4 100644 --- a/VideoAnalysisCore/Job/NodePackageJob.cs +++ b/VideoAnalysisCore/Job/NodePackageJob.cs @@ -47,10 +47,19 @@ namespace VideoAnalysisCore.Job var taskArr = await nodePackageInfoDB.AsQueryable() .Where(s => s.SuccessTime == null) .ToArrayAsync(); - var videoIdArr = await videoTaskDB.AsQueryable() + var videoArr = await videoTaskDB.AsQueryable() .Where(s => s.EndTime != null) - .Select(s => s.TagId) + .Select(s =>new VideoTask { + Id = s.Id, + TagId = s.TagId, + VideoType=s.VideoType + }) .ToArrayAsync(); + var videoDic = videoArr + .Where(s=>s.TagId != null) + .GroupBy(s => s.TagId!) + .ToDictionary(s => s.Key,s=>s.First()); + var videoIdArr = videoArr.Select(s => s.TagId).ToArray(); var videoPPTArr = await videoTaskDB.AsQueryable() .Where(s => s.EndTime != null) @@ -59,8 +68,15 @@ namespace VideoAnalysisCore.Job var postData = new List(); foreach (var item in taskArr) { - if (videoIdArr.Contains(item.VideoCode)|| videoPPTArr.Contains(item.VideoCode)) + if (videoIdArr.Contains(item.VideoCode) || videoPPTArr.Contains(item.VideoCode)) { + if (videoDic.ContainsKey(item.VideoCode)) + { + var v = videoDic[item.VideoCode]; + if (v.VideoType!=null && v.VideoType != item.CourseType) + item.CourseType = v.VideoType.Value;//额外同步课程类型[新课 复习课] + } + postData.Add(item); item.SuccessTime = DateTime.Now; } diff --git a/VideoAnalysisCore/Model/Enum/RedisChannelEnum.cs b/VideoAnalysisCore/Model/Enum/RedisChannelEnum.cs index 00548af..fe9b1b7 100644 --- a/VideoAnalysisCore/Model/Enum/RedisChannelEnum.cs +++ b/VideoAnalysisCore/Model/Enum/RedisChannelEnum.cs @@ -25,6 +25,11 @@ ///// 解析说话人 ///// //解析说话人 = 30, + + /// + /// AI课程类型 + /// + AI课程类型 = 31, /// /// Chat模型分析 /// diff --git a/VideoAnalysisCore/Model/NodePackageInfo.cs b/VideoAnalysisCore/Model/NodePackageInfo.cs index d7041ca..faa78ed 100644 --- a/VideoAnalysisCore/Model/NodePackageInfo.cs +++ b/VideoAnalysisCore/Model/NodePackageInfo.cs @@ -75,7 +75,7 @@ namespace VideoAnalysisCore.Model /// /// 通知回调地址 /// - [SugarColumn(Length = 500)] + [SugarColumn(IsNullable = true,Length = 500)] public string CallBackUrl { get; set; } /// /// 请求区域