diff --git a/VideoAnalysis/Components/Pages/VideoTaskPage.razor b/VideoAnalysis/Components/Pages/VideoTaskPage.razor index 7945f48..dc2bb05 100644 --- a/VideoAnalysis/Components/Pages/VideoTaskPage.razor +++ b/VideoAnalysis/Components/Pages/VideoTaskPage.razor @@ -8,6 +8,7 @@ @using VideoAnalysisCore.Model.Dto @using VideoAnalysisCore.Model.Enum; + - + @@ -50,25 +51,25 @@ - + + Description="@RowST(rowData,RedisChannelEnum.下载文件)" /> + Description="@RowST(rowData,RedisChannelEnum.分离音频)" /> + Description="@RowST(rowData,RedisChannelEnum.解析字幕)" /> - - + + + Description="@RowST(rowData,RedisChannelEnum.结束任务)" /> @@ -101,4 +102,4 @@

- + \ No newline at end of file diff --git a/VideoAnalysis/Components/Pages/VideoTaskPage.razor.cs b/VideoAnalysis/Components/Pages/VideoTaskPage.razor.cs index f66a4c8..e5f3890 100644 --- a/VideoAnalysis/Components/Pages/VideoTaskPage.razor.cs +++ b/VideoAnalysis/Components/Pages/VideoTaskPage.razor.cs @@ -128,8 +128,8 @@ namespace Learn.VideoAnalysis.Components.Pages var data = RedisExpand.Redis.HMGet(RedisExpandKey.Task(item.Id), "Progress", "LastEnum", "StartTime", "ErrorMessage"); item.Progress = data[0]; - item.LastEnum = data[1].ToEnum() ?? default; - item.StartTimeDic = System.Text.Json.JsonSerializer.Deserialize>(data[2]) ?? null; + item.LastEnum = data[1] == null ?default:data[1].ToEnum() ?? default; + item.StartTimeDic = data[2]==null?null: System.Text.Json.JsonSerializer.Deserialize>(data[2]) ?? null; item.ErrorMessage = data[3]; rowRestartLoading = false; var statusStr = "wait"; diff --git a/VideoAnalysis/Components/Pages/VideoTaskShow.razor.cs b/VideoAnalysis/Components/Pages/VideoTaskShow.razor.cs index 12d5be4..164728c 100644 --- a/VideoAnalysis/Components/Pages/VideoTaskShow.razor.cs +++ b/VideoAnalysis/Components/Pages/VideoTaskShow.razor.cs @@ -95,7 +95,7 @@ namespace Learn.VideoAnalysis.Components.Pages }).ToArray(); videoPath = AppCommon.GetVideoPath(nowTask.Id.ToString()); - if (nowTask.VideoType == AttachmentsInfoType.Review) + if (nowTask.VideoType == AttachmentsInfoType.复习) { var questionArr = await videoQuestionDB .AsQueryable().Where(s => s.VideoTaskId == nowTask.Id) diff --git a/VideoAnalysis/Program.cs b/VideoAnalysis/Program.cs index 25a8e03..3cf4074 100644 --- a/VideoAnalysis/Program.cs +++ b/VideoAnalysis/Program.cs @@ -4,7 +4,6 @@ using Microsoft.OpenApi.Models; using VideoAnalysisCore.AICore.SherpaOnnx; using Mapster; using VideoAnalysisCore.AICore.GPT; -using VideoAnalysisCore.AICore.GPT.KIMI; using VideoAnalysisCore.AICore.GPT.ChatGPT; using Microsoft.Extensions.FileProviders; using VideoAnalysisCore.AICore.GPT.DeepSeek; diff --git a/VideoAnalysisCore/AICore/GPT/BserGPT.cs b/VideoAnalysisCore/AICore/GPT/BserGPT.cs index 0c46d53..855fddf 100644 --- a/VideoAnalysisCore/AICore/GPT/BserGPT.cs +++ b/VideoAnalysisCore/AICore/GPT/BserGPT.cs @@ -16,5 +16,11 @@ namespace VideoAnalysisCore.AICore.GPT /// 任务id /// public Task GetKnow(string task); + /// + /// 获取 视频分段内的 试题 + /// + /// 任务id + /// + public Task GetVideoQuestion(string task); } } diff --git a/VideoAnalysisCore/AICore/GPT/ChatGPT/Chat_GPT.cs b/VideoAnalysisCore/AICore/GPT/ChatGPT/Chat_GPT.cs index 9b78718..fc84ad9 100644 --- a/VideoAnalysisCore/AICore/GPT/ChatGPT/Chat_GPT.cs +++ b/VideoAnalysisCore/AICore/GPT/ChatGPT/Chat_GPT.cs @@ -418,5 +418,10 @@ namespace VideoAnalysisCore.AICore.GPT.ChatGPT return gptRes; } + + public Task GetVideoQuestion(string task) + { + throw new NotImplementedException(); + } } } diff --git a/VideoAnalysisCore/AICore/GPT/DeepSeek/DeepSeekClient.cs b/VideoAnalysisCore/AICore/GPT/DeepSeek/DeepSeekClient.cs index 978e454..4bbfbde 100644 --- a/VideoAnalysisCore/AICore/GPT/DeepSeek/DeepSeekClient.cs +++ b/VideoAnalysisCore/AICore/GPT/DeepSeek/DeepSeekClient.cs @@ -7,7 +7,6 @@ using System.Net.Http; using Newtonsoft.Json; using System.Net.Http.Json; using System.Net; -using VideoAnalysisCore.AICore.GPT.KIMI; using System.Threading; using System; using System.IO; @@ -121,8 +120,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek Console.WriteLine(e.Message); Console.WriteLine(e.StackTrace); Console.WriteLine("=============================================="); - - Thread.Sleep(1000); + Thread.Sleep(1000); } } throw errorMSG.Last(s => s != null); diff --git a/VideoAnalysisCore/AICore/GPT/DeepSeek/DeepSeekModel.cs b/VideoAnalysisCore/AICore/GPT/DeepSeek/DeepSeekModel.cs index 2e4b41c..3e6df08 100644 --- a/VideoAnalysisCore/AICore/GPT/DeepSeek/DeepSeekModel.cs +++ b/VideoAnalysisCore/AICore/GPT/DeepSeek/DeepSeekModel.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -using VideoAnalysisCore.AICore.GPT.KIMI; namespace VideoAnalysisCore.AICore.GPT.DeepSeek { diff --git a/VideoAnalysisCore/AICore/GPT/DeepSeek/DeepSeek_GPT.cs b/VideoAnalysisCore/AICore/GPT/DeepSeek/DeepSeek_GPT.cs index 4aaab68..964e024 100644 --- a/VideoAnalysisCore/AICore/GPT/DeepSeek/DeepSeek_GPT.cs +++ b/VideoAnalysisCore/AICore/GPT/DeepSeek/DeepSeek_GPT.cs @@ -556,10 +556,50 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek await RedisExpand.Redis .HMSetAsync(RedisExpandKey.Task(task), "VideoKnows", questionRes); - if (taskInfo.VideoType == AttachmentsInfoType.复习) - await AnalysisVideoQuestions(taskInfo, knowledgeInfos); - return null; } + + + /// + /// 获取 视频分段内的 试题 + /// + /// 任务id + /// + public async Task GetVideoQuestion(string task) + { + var taskId = long.Parse(task); + var taskInfo = await videoTaskDB.AsQueryable() + .Where(s => s.Id == taskId) + .FirstAsync(); + + if (taskInfo.VideoType != AttachmentsInfoType.复习) + return; + var subject = taskInfo.Subject.ToString(); + var Course_Id = 27; + switch (taskInfo.Type)//处理不同任务类型的知识点树 + { + case TaskTypeEnum.蓝鲸智库_中职视频分段: + Course_Id = 51; + break; + case TaskTypeEnum.蓝鲸智库_视频分段: + default: + Course_Id = 27; + break; + } + + 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); + if (know is null) + throw new Exception("未能找到对应知识点=>" + sections); + var kInfo = await knowledgeInfoDB.GetByIdAsync(know.Parent_Id); + var knowledgeInfos = await knowledgeInfoDB.AsQueryable() + .ToChildListAsync(s => s.Parent_Id, kInfo.Parent_Id == 0 ? kInfo.Id : kInfo.Parent_Id); + //开始分析复习课 试题 + await AnalysisVideoQuestions(taskInfo, knowledgeInfos); + + return; + } } } diff --git a/VideoAnalysisCore/AICore/GPT/KIMI/KIMI_GPT.cs b/VideoAnalysisCore/AICore/GPT/KIMI/KIMI_GPT.cs deleted file mode 100644 index 2d6b9c4..0000000 --- a/VideoAnalysisCore/AICore/GPT/KIMI/KIMI_GPT.cs +++ /dev/null @@ -1,229 +0,0 @@ -using VideoAnalysisCore.AICore.SherpaOnnx; -using VideoAnalysisCore.Common; -using System.Threading.Tasks; -using Whisper.net; -using System.Text.Json; -using VideoAnalysisCore.Model; -using System.Text; -using FFmpeg.NET.Services; -using Microsoft.Extensions.Primitives; -using System.ComponentModel.DataAnnotations; -using System.Reflection; -using FreeRedis; -using VideoAnalysisCore.Model.Dto; -using SqlSugar.IOC; -using VideoAnalysisCore.AICore.GPT.Dto; -using VideoAnalysisCore.AICore.GPT; -using VideoAnalysisCore.AICore.GPT.ChatGPT; -using VideoAnalysisCore.Model.Enum; - -namespace VideoAnalysisCore.AICore.GPT.KIMI -{ - /// - /// kimi 文本模型 - /// - public class KIMI_GPT // : IBserGPT - { - private readonly MoonshotClient moonshotClient; - private readonly Repository criteriaDB; - private readonly Repository videoTaskDB; - /// - /// 初始化 - /// - /// - /// - public KIMI_GPT(MoonshotClient moonshotClient, Repository criteria, Repository videoTaskDB) - { - MoonshotClient.Host = AppCommon.Config.ChatGpt.KIMI.Host; - MoonshotClient.ApiKey = AppCommon.Config.ChatGpt.KIMI.ApiKey; - - this.moonshotClient = moonshotClient; - criteriaDB = criteria; - this.videoTaskDB = videoTaskDB; - } - /// - /// 访问GPT - /// - /// 任务id - /// - public async Task CallGPT(string task) - { - var taskId = long.Parse(task); - var taskInfo = await videoTaskDB.AsQueryable() - .Where(s => s.Id == taskId) - .FirstAsync(); - var speakerArr = JsonSerializer.Deserialize(taskInfo.Speaker); - var captionsArr = JsonSerializer.Deserialize(taskInfo.Captions); - var captions = ExpandFunction.GetSpeakerCaptions(captionsArr, speakerArr); - var criteriaArr = await criteriaDB.GetListAsync(s => s.Subject == taskInfo.Subject); - var criteriaBuilder = new StringBuilder(); - foreach (var item in criteriaArr) - { - criteriaBuilder.Append(item.Id); - criteriaBuilder.Append(":"); - criteriaBuilder.Append(item.NamePrompt); - criteriaBuilder.Append("? 请基于问题的回答苛刻的给出[优/良/中/差]作为得分"); - //criteriaBuilder.Append("0-"); - //criteriaBuilder.Append((int)(item.TotalScore * 10)); - //criteriaBuilder.Append("分"); - //criteriaBuilder.Append((int)(item.PassScore * 10)); - //criteriaBuilder.Append("分为及格"); - criteriaBuilder.Append(":"); - criteriaBuilder.Append("array=[得分,问题的回答,问题的详细改进意见,问题的详细扣分原因]|"); - - } - //拼接枚举提问 - foreach (var value in System.Enum.GetValues(typeof(QuestionTypeEnum))) - { - var enumValue = (QuestionTypeEnum)value; - var displayAttribute = enumValue.GetType() - .GetField(enumValue.ToString())? - .GetCustomAttribute(); - if (displayAttribute == null) continue; - criteriaBuilder.Append(enumValue.GetHashCode()); - criteriaBuilder.Append(":"); - criteriaBuilder.Append(displayAttribute.Prompt); - criteriaBuilder.Append("|"); - } - - var resFormat = """{"问题编号":number,"结果":array|bool|object,"问题解释":string}"""; - var postMessages = - $"你是一个教学经验老道老师对教学工作有着深入的理解和丰富的经验,能够准确把握教学大纲的要求和教学重点。" + - $"熟练掌握各种教学管理方法和手段,能够制定科学合理的教学计划和教学评估体系。" + - $"善于发现教学中的问题,并能迅速提出有效的解决方案,确保教学工作的顺利进行。" + - $"以下是一段音频的字幕,分析这段字幕 字幕格式(说话人:开始秒:结束秒:内容|下一段字幕)." + - $"字幕列表 {captions.Captions} " + - $"基于字幕内容回答提出的所有问题 问题格式(问题编号:问题描述:结束秒:结果类型|下一个问题)" + - $"问题列表 {criteriaBuilder} " - + $"返回固定的JSON数组格式({resFormat})"; - - - var reqTokenCount = await moonshotClient.GetAsTiMateTokenCount(postMessages); - var maxTokens = 4000; - var modelId = reqTokenCount > 32 * 1000 - maxTokens ? "moonshot-v1-128k" : "moonshot-v1-32k"; - var chatRep = new ChatReq - { - max_tokens = maxTokens, - temperature = 0.3f, - frequency_penalty = 0, - presence_penalty = 0, - model = modelId, - messages = new List(){ - new MessagesItem(postMessages,"system"), - //new MessagesItem(resFormat,"assistant",true), - } - }; - - var time = DateTime.Now.ToString("MMddHHmmss"); - RedisExpand.SetTaskGPTCached(task, time,chatRep); - var chatResp = await moonshotClient.ChatSSE(chatRep); - //chatResp = await moonshotClient.Chat(chatRep); - var chatResContent = chatResp?.res; - if (string.IsNullOrEmpty(chatResContent)) - throw new Exception("KIMIGPT返回message无效结果"); - if (chatResp != null) - RedisExpand.SetTaskGPTCached(task, time, new object[] { chatResp.Value.res, chatResp.Value.u }); - //chatResContent = """[{ "问题编号": 10, "结果": [ "良", "教学目标在授课中有提及,如提到了圆锥曲线的学习以及数列的概念和简单表示,但未明确指出具体的教学目标,如学生应掌握的具体知识点或技能。", "教师可以在课程开始时明确列出本节课的教学目标,让学生清楚知道本节课的学习重点。", "教学目标不够明确,缺乏具体的教学目标描述。" ], "问题解释": "授课中提到了学习圆锥曲线和数列的概念及简单表示,但未明确具体的教学目标。"},{ "问题编号": 11, "结果": [ "优", "授课语言简明、准确,且在解释概念时使用了生动的例子,如通过王芳同学的身高数据来解释数列的概念。", "无需改进,授课语言已经非常清晰和生动。", "无" ], "问题解释": "授课中使用了简明、准确、生动的语言,并通过实例来解释概念。"},{ "问题编号": 12, "结果": [ "优", "教师在授课过程中表现出对学生的重视,语言友善温和,如在解释概念时多次询问学生是否理解。", "无需改进,教师已经很好地表现出对学生的重视和友善。", "无" ], "问题解释": "教师在授课中重视学生需求,表现出友善和温和的态度。"},{ "问题编号": 13, "结果": [ "良", "授课中教师给学生留有一定的思考时间,但部分时间较短,可能不足以让学生充分思考。", "教师可以在解释概念或提出问题后,适当延长学生的思考时间,确保学生能够充分理解和消化。", "部分思考留白时间较短,不足以让学生充分思考。" ], "问题解释": "授课中给学生留有思考时间,但部分时间较短。"},{ "问题编号": 14, "结果": [ "优", "教学重难点突出,如对数列的概念、表示方法等进行了详细讲解,并使用了实例来帮助学生理解。", "无需改进,教学重难点已经很好地突出。", "无" ], "问题解释": "教学中对重难点进行了突出讲解,并使用实例帮助学生理解。"},{ "问题编号": 15, "结果": [ "中", "学生在授课中的参与度一般,教师虽有询问学生是否理解,但缺乏更积极的互动方式。", "教师可以通过提问、让学生回答问题等方式,增加学生的参与度和互动。", "学生参与度一般,缺乏更积极的互动。" ], "问题解释": "授课中教师虽有询问学生是否理解,但学生参与互动的程度一般。"},{ "问题编号": 16, "结果": [ "优", "知识点讲解逻辑清晰明了,如对数列的概念、分类、表示方法等进行了条理清晰的讲解。", "无需改进,知识点讲解逻辑已经非常清晰。", "无" ], "问题解释": "授课中知识点讲解逻辑清晰明了,条理性强。"},{ "问题编号": 17, "结果": [ "良", "例题讲解过程中,教师进行了一定的留白,但留白的时间和深度可以进一步加强。", "教师可以在例题讲解中设置更多的问题,引导学生思考,增加留白的时间和深度。", "例题讲解中的留白时间和深度有待加强。" ], "问题解释": "授课中例题讲解进行了留白,但可以进一步加强。"},{ "问题编号": 18, "结果": [ "良", "练习时给到学生的时间一般,部分练习时间较短,可能不足以让学生充分练习。", "教师可以在练习环节给学生更多的时间,确保学生能够充分练习和理解。", "练习时间部分较短,不足以让学生充分练习。" ], "问题解释": "授课中练习环节给到学生的时间一般。"},{ "问题编号": 19, "结果": [ "优", "课程内容不冗杂,讲解清楚,如对数列的概念、分类、表示方法等进行了清晰的讲解。", "无需改进,课程内容和讲解已经非常清晰。", "无" ], "问题解释": "授课中课程内容不冗杂,讲解清楚。"},{ "问题编号": 20, "结果": [ "优", "授课中进行了举例阐述知识点,如通过王芳同学的身高数据来解释数列的概念,便于学生理解。", "无需改进,授课中已经很好地使用了举例来阐述知识点。", "无" ], "问题解释": "授课中使用了举例来阐述知识点,便于学生理解。"},{ "问题编号": 5001, "结果": [ "数列", "圆锥曲线", "学习", "例子", "身高", "数据", "表示", "函数", "同向公式" ], "问题解释": "分析了授课中的高频词,提取了出现频率最高的10个词汇。"},{ "问题编号": 5002, "结果": [ { "Start": 0, "End": 120, "Content": "课程开始,教师介绍了圆锥曲线的学习情况,并提到了数列的学习。" }, { "Start": 120, "End": 240, "Content": "教师详细讲解了数列的概念,并通过王芳同学的身高数据作为例子。" }, { "Start": 240, "End": 360, "Content": "教师解释了数列的分类,包括递增数列、递减数列和常数列,并给出了相应的定义。" }, { "Start": 360, "End": 480, "Content": "教师讨论了数列的表示方法,包括列表法、图像法和通项公式,并提供了相应的例子。" } ], "问题解释": "基于课堂情况提取了课堂上的事件,并分析了每个事件的时间片段和内容概览。"},{ "问题编号": 5003, "结果": { "重复回答": 3, "老师追问": 5, "简单性表扬": 2, "老师补充答案": 4, "表扬并补充答案": 1 }, "问题解释": "统计了授课中教师回答类型的次数,包括重复回答、老师追问、简单性表扬、老师补充答案和表扬并补充答案。"},{ "问题编号": 5004, "结果": [ { "Start": 150, "End": 180, "Content": "独立学习" }, { "Start": 300, "End": 330, "Content": "小组合作" }, { "Start": 450, "End": 480, "Content": "随堂练习" } ], "问题解释": "分析了授课中教师提到独立学习、小组合作和随堂练习的时间段,并提取了相应的字幕开始秒和结束秒。"}]"""; - - chatResContent = chatResContent?.Replace("字幕内容", "课堂情况"); - chatResContent = chatResContent?.Replace("\n", ""); - chatResContent = chatResContent?.Replace("}{", "},{"); - chatResContent = chatResContent?.Replace("}|{", "},{"); - chatResContent = chatResContent?.Trim(); - if (!chatResContent.StartsWith("[")) - chatResContent = "[" + chatResContent; - if (!chatResContent.EndsWith("]")) - chatResContent = chatResContent + "]"; - var questionRes = JsonSerializer.Deserialize(chatResContent); - var gptRes = new TaskRes(captions); - if (questionRes is null) - throw new Exception("KIMIGPT返回无效结果"); - var qEnum = (int)QuestionTypeEnum.高频词; - //处理 ai问答提问 - var arr1 = questionRes.Where(s => s.问题编号 < qEnum); - var arr2 = questionRes.Where(s => s.问题编号 >= qEnum) - .ToDictionary(s => s.问题编号); - //AI综合评估 - var criteriaDic = criteriaArr.ToDictionary(s => s.Id); - - var random = new Random(); - var ccArr = new List(arr1.Count()); - foreach (var s in arr1) //处理问题 - { - var Id = criteriaDic[s.问题编号].Id; - var PassScore = criteriaDic[s.问题编号].PassScore; - var TotalScore = criteriaDic[s.问题编号].TotalScore; - var Score = Math.Round(criteriaDic[s.问题编号].TotalScore * 0.01m - * ((int)(s.ToObject()?[0].ToEnum() ?? ScoreTypeEnum.中) - + random.Next(-6, 25)), - 1, MidpointRounding.AwayFromZero); - var Prompt = s.ToObject()?[1].ToString() ?? string.Empty; - var ImprovedMethods = s.ToObject()?[2].ToString() ?? string.Empty; - var Analyze = s.问题解释 ?? string.Empty; - var kf = s.ToObject()?[3].ToString() ?? string.Empty; - kf = kf.Replace("无", ""); - if (string.IsNullOrEmpty(kf)) - Score = criteriaDic[s.问题编号].TotalScore; - else - Analyze += " 扣分原因:" + kf; - ccArr.Add(new CourseCriteria() - { - Analyze = Analyze, - Id = Id, - PassScore = PassScore, - ImprovedMethods = ImprovedMethods, - Prompt = Prompt, - Score = Score, - TotalScore = TotalScore, - }); - } - gptRes.Assessment = new AssessmentDto() - { - Bad = ccArr.Where(s => s.Score < s.PassScore).ToArray(), - Merit = ccArr.Where(s => s.Score >= s.PassScore).ToArray(), - }; - //高频词汇 - gptRes.Hotwords = arr2[(int)QuestionTypeEnum.高频词].ToObject() ?? ["暂无数据"]; - - //时间段概览 - gptRes.TimeOverview = arr2[(int)QuestionTypeEnum.时间段概览] - .ToObject(); - //提问类型 - gptRes.QuestionType = arr2[(int)QuestionTypeEnum.提问类型] - .ToObject>(); - - //分析上课时间段情况 分析 独立学习 小组合作 随堂练习等情况 - var extraTimeBase = arr2[(int)QuestionTypeEnum.额外课堂情况] - .ToObject(); - if (extraTimeBase is not null) - foreach (var item in extraTimeBase) - { - if (item is null) - continue; - var r = item.Content.ToEnum(); - if (r is null) - continue; - var arr = gptRes.TimeBase? - .Where(s => s.Start >= item.Start && s.End <= item.End); - if (arr is null) - continue; - foreach (var s in arr) - s.TimeBaseType = r; - } - var totalTokens = chatResp?.u.total_tokens ?? 0; - if (totalTokens > 1) - { - var tid = long.Parse(task); - await videoTaskDB.AsUpdateable() - .SetColumns(it => it.TotalTokens == totalTokens)//SetColumns是可以叠加的 写2个就2个字段赋值 - .Where(it => it.Id == tid) - .ExecuteCommandAsync(); - } - - await RedisExpand.Redis - .HMSetAsync(RedisExpandKey.Task(task), "ChatAnalysis", gptRes); - - return gptRes; - } - } -} diff --git a/VideoAnalysisCore/AICore/GPT/KIMI/MoonshotClient.cs b/VideoAnalysisCore/AICore/GPT/KIMI/MoonshotClient.cs deleted file mode 100644 index 20f255b..0000000 --- a/VideoAnalysisCore/AICore/GPT/KIMI/MoonshotClient.cs +++ /dev/null @@ -1,356 +0,0 @@ -using VideoAnalysisCore.Common; -using System.Net.Http.Headers; -using System.Text; -using Microsoft.Extensions.Logging; -using Newtonsoft.Json.Linq; -using System.Net.Http; -using Newtonsoft.Json; -using System.Net.Http.Json; -using System.Net; -using Azure; -using System.Reflection.PortableExecutable; -using static System.Runtime.InteropServices.JavaScript.JSType; - -/// -/// https://platform.moonshot.cn/docs/api-reference -/// -namespace VideoAnalysisCore.AICore.GPT.KIMI -{ - - public class MoonshotClient - { - private readonly ILogger _logger; - - private readonly IHttpClientFactory _httpClientFactory; - - public MoonshotClient(ILogger logger, IHttpClientFactory httpClientFactory) - { - _logger = logger; - _httpClientFactory = httpClientFactory; - } - - /// - /// list models - /// - /// - public async Task ListModels() - { - var response = await GetAsync("/v1/models"); - return await ParseResp(response); - } - - /// - /// Chat - /// - /// - /// Return HttpResponseMessage for SSE - public async Task Chat(string requestBody) - { - var chatResp = await PostJsonStreamAsync("/v1/chat/completions", requestBody); - return await chatResp.Content.ReadFromJsonAsync(); - - } - - /// - /// ChatSSE[流式传输 更稳定] - /// - /// - /// Return HttpResponseMessage for SSE - public async Task<(Usage u, string res)?> ChatSSE(ChatReq chatReq) - { - chatReq.stream = true; - var requestBody = System.Text.Json.JsonSerializer.Serialize(chatReq); - var chatResp = await PostJsonStreamAsync("/v1/chat/completions", requestBody); - using var stream = await chatResp.Content.ReadAsStreamAsync(); - using var reader = new StreamReader(stream, Encoding.UTF8); - string line; - StringBuilder messageBuilder = new StringBuilder(); - ChatResSSE lastChat = new ChatResSSE(); - while ((line = await reader.ReadLineAsync()) != null) - { - if (line.EndsWith("[DONE]")) - { - // 表示一条消息结束 - string message = messageBuilder.ToString(); - messageBuilder.Clear(); - var u = lastChat?.choices?.FirstOrDefault()?.usage; - if (u == null || string.IsNullOrEmpty(message)) - return null; - return (u, message); - } - else if (line.StartsWith("data:")) - { - try - { - var data = System.Text.Json.JsonSerializer.Deserialize(line.Substring("data:".Length).Trim()); - lastChat = data; - var str = data?.choices.FirstOrDefault()?.delta.content; - if (!string.IsNullOrEmpty(str)) - messageBuilder.Append(str); - } - catch (Exception e) - { - Console.WriteLine("异常 ChatSSE=>"); - Console.WriteLine(line); - Console.WriteLine(e.Message); - Console.WriteLine(e.StackTrace); - } - } - } - return null; - } - - /// - /// Chat - /// - /// - /// Return HttpResponseMessage for SSE - public async Task<(Usage u, string res)?> Chat(ChatReq chatReq) - { - var requestBody = System.Text.Json.JsonSerializer.Serialize(chatReq); - var chatResp = await PostJsonStreamAsync("/v1/chat/completions", requestBody); - var res = await chatResp.Content.ReadFromJsonAsync(); - var chatResContent = res?.choices.FirstOrDefault()?.message.content.Trim(); - - if (res is null || res.error != null) - throw new Exception($"KIMI模型返回异常 Chat 返回参数: " + - $" {System.Text.Json.JsonSerializer.Serialize(res)}"); - - if (string.IsNullOrEmpty(chatResContent)) - return null; - - - return (res.usage, chatResContent); - } - - /// - /// 计算token长度 - /// - /// 文本 - /// - /// - public async Task GetAsTiMateTokenCount(string chatReqText) - { - var reqObject = new - { - model = "moonshot-v1-128k", - messages = new List() - { - new MessagesItem(chatReqText,"system"), - } - }; - var response = await PostJsonStreamAsync("/v1/tokenizers/estimate-token-count", JsonConvert.SerializeObject(reqObject)); - var responseText = await response.Content.ReadAsStringAsync(); - if (response.IsSuccessStatusCode) - { - var responseObj = JToken.Parse(responseText); - return responseObj?["data"]?["total_tokens"]?.ToObject(); - } - var error = JsonConvert.DeserializeObject(responseText); - _logger.LogError($"{error?.error?.type}: {error?.error?.message}"); - throw new Exception($"{error?.error.type}: {error?.error.message}"); - } - - - /// - /// Get as timate token count - /// - /// - /// - public async Task GetAsTiMateTokenCount(ChatReq chatReq) - { - var chatReqText = JsonConvert.SerializeObject(chatReq); - return await GetAsTiMateTokenCount(chatReqText); - } - - - /// - /// List files - /// - public virtual async Task ListFiles() - { - var response = await GetAsync("/v1/files"); - return await ParseResp(response); - } - - - - - - /// - /// Upload file - /// - public virtual async Task UploadFile(string filePath) - { - if (!File.Exists(filePath)) - { - throw new FileNotFoundException($"{filePath} not found"); - } - var client = _httpClientFactory.CreateClient(); - client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", ApiKey); - var request = new HttpRequestMessage(HttpMethod.Post, $"{Host}/v1/files"); - var content = new MultipartFormDataContent - { - { new StreamContent(File.OpenRead(filePath)), "file", filePath } - }; - request.Content = content; - var response = await client.SendAsync(request); - return await ParseResp(response); - } - - - - /// - /// Upload file stream - /// - public virtual async Task UploadFileStream(Stream stream, string fileName) - { - var client = _httpClientFactory.CreateClient(); - client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", ApiKey); - var request = new HttpRequestMessage(HttpMethod.Post, $"{Host}/v1/files"); - var content = new MultipartFormDataContent - { - { new StreamContent(stream), "file", fileName } - }; - request.Content = content; - var response = await client.SendAsync(request); - return await ParseResp(response); - } - - - /// - /// Get file content - /// - - public virtual async Task GetFileContent(string fileId) - { - var response = await GetAsync($"/v1/files/{fileId}/content"); - return await ParseResp(response); - } - - - private async Task GetAsync(string path) - { - var client = _httpClientFactory.CreateClient(); - client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", ApiKey); - return await client.GetAsync(Host + path); - } - - private async Task PostJsonAsync(string path, string json) - { - var client = _httpClientFactory.CreateClient(); - client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", ApiKey); - return await client.PostAsync(Host + path, new StringContent(json, Encoding.UTF8, "application/json")); - } - - private async Task PostJsonStreamAsync(string path, string json) - { - var uriBuilder = new UriBuilder(Host + path); - var maxRestart = 4; - var errorMSG = new Exception[maxRestart]; - for (int i = 0; i < maxRestart; i++) - { - try - { - var client = _httpClientFactory.CreateClient(); - client.Timeout = TimeSpan.FromSeconds(Timeout.Infinite);//超时时间20分钟 - client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", ApiKey); - client.DefaultRequestVersion = HttpVersion.Version20; - client.DefaultVersionPolicy = HttpVersionPolicy.RequestVersionOrLower; - client.DefaultRequestHeaders.ConnectionClose = true; - - //var request = ToHttpRequest(path); - //request.Version = HttpVersion.Version20; - //request.VersionPolicy = HttpVersionPolicy.RequestVersionOrLower; - //request.Content = new StringContent(json, Encoding.UTF8, "application/json"); - //return await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead); - - var content = new StringContent(json, Encoding.UTF8, "application/json"); - return await client.PostAsync(uriBuilder.Uri, content); - } - catch (Exception e) - { - errorMSG[i] = e; - Console.WriteLine("====================[请求异常,重试]===================="); - Console.WriteLine(uriBuilder.Uri); - Console.WriteLine(e.Message); - Console.WriteLine(e.StackTrace); - Console.WriteLine("=============================================="); - - } - Thread.Sleep(1000); - } - throw errorMSG.Last(s => s != null); - } - - private HttpRequestMessage ToHttpRequest(string path) - { - var request = new HttpRequestMessage(); - var uriBuilder = new UriBuilder(Host + path); - request.RequestUri = uriBuilder.Uri; - request.Method = new HttpMethod("POST"); - request.Headers.Host = new Uri(Host).Host; - return request; - } - - - - /// - /// Parse response - /// - private async Task ParseResp(HttpResponseMessage response) - { - var responseText = await response.Content.ReadAsStringAsync(); - if (response.IsSuccessStatusCode) - { - return JsonConvert.DeserializeObject(responseText) ?? default; - } - var error = JsonConvert.DeserializeObject(responseText); - _logger.LogError($"{error?.error.type}: {error?.error.message}"); - throw new Exception($"{error?.error.type}: {error?.error.message}"); - } - - - - private static string _host = "https://api.moonshot.cn"; - - public static string Host - { - get - { - if (string.IsNullOrEmpty(_host) && !string.IsNullOrEmpty(AppCommon.Config.ChatGpt.KIMI.Host)) - { - _host = AppCommon.Config.ChatGpt.KIMI.Host ?? ""; - } - - return _host; - } - set - { - - _host = value; - } - } - - - private static string _apiKey = "sk_"; - - public static string ApiKey - { - get - { - if (string.IsNullOrEmpty(_apiKey) && !string.IsNullOrEmpty(AppCommon.Config.ChatGpt.KIMI.ApiKey)) - { - _apiKey = AppCommon.Config.ChatGpt.KIMI.ApiKey ?? ""; - } - - return _apiKey; - } - set - { - _apiKey = value; - } - } - - } -} \ No newline at end of file diff --git a/VideoAnalysisCore/AICore/GPT/KIMI/MoonshotModel.cs b/VideoAnalysisCore/AICore/GPT/KIMI/MoonshotModel.cs deleted file mode 100644 index cbb3dc5..0000000 --- a/VideoAnalysisCore/AICore/GPT/KIMI/MoonshotModel.cs +++ /dev/null @@ -1,365 +0,0 @@ -namespace VideoAnalysisCore.AICore.GPT.KIMI -{ - - public class MessagesItem - { - public MessagesItem() - { - - } - public MessagesItem(string content, string role = "user", bool partial = false) - { - this.content = content; - this.role = role; - this.partial = partial; - } - /// - /// - /// - public string role { get; set; } - public bool partial { get; set; } = false; - - /// - /// - /// - public string content { get; set; } - } - /// - /// chat请求参数 - /// - public class ChatReq - { - /// - /// 使用的模型 - /// 例如[ moonshot-v1-8k ] - /// - public string model { get; set; } = "moonshot-v1-8k"; - /// - /// 消息主体 - /// - public List messages { get; set; } - /// - /// 使用什么采样温度,介于 0 和 1 之间。较高的值(如 0.7)将使输出更加随机,而较低的值(如 0.2)将使其更加集中和确定性 - /// 默认为 0,如果设置,值域须为 [0, 1] 我们推荐 0.3,以达到较合适的效果 - /// - public float temperature { get; set; } - - /// - /// 聊天完成时生成的最大 token 数。如果到生成了最大 token 数个结果仍然没有结束,finish reason 会是 "length", 否则会是 "stop" - /// 这个值建议按需给个合理的值,如果不给的话,我们会给一个不错的整数比如 1024。特别要注意的是,这个 max_tokens 是指您期待我们返回的 token 长度,而不是输入 + 输出的总长度。比如对一个 moonshot-v1-8k 模型,它的最大输入 + 输出总长度是 8192,当输入 messages 总长度为 4096 的时候,您最多只能设置为 4096,否则我们服务会返回不合法的输入参数( invalid_request_error ),并拒绝回答。如果您希望获得“输入的精确 token 数”,可以使用下面的“计算 Token” API 使用我们的计算器获得计数 - /// - public int? max_tokens { get; set; } - /// - /// 另一种采样方法,即模型考虑概率质量为 top_p 的标记的结果。因此,0.1 意味着只考虑概率质量最高的 10% 的标记。一般情况下,我们建议改变这一点或温度,但不建议 同时改变 - /// - public float? top_p { get; set; } = 1.0f; - /// - /// 为每条输入消息生成多少个结果 - /// 默认为 1,不得大于 5。特别的,当 temperature 非常小靠近 0 的时候,我们只能返回 1 个结果,如果这个时候 n 已经设置并且 > 1,我们的服务会返回不合法的输入参数(invalid_request_error) - /// - public int? n { get; set; } = 1; - /// - /// 存在惩罚,介于-2.0到2.0之间的数字。正值会根据新生成的词汇是否出现在文本中来进行惩罚,增加模型讨论新话题的可能性 - /// 默认为 0 - /// - public float? presence_penalty { get; set; } = 0; - /// - /// 频率惩罚,介于-2.0到2.0之间的数字。正值会根据新生成的词汇在文本中现有的频率来进行惩罚,减少模型一字不差重复同样话语的可能性 - /// 默认为 0 - /// - public float? frequency_penalty { get; set; } = 0; - /// - /// 停止词,当全匹配这个(组)词后会停止输出,这个(组)词本身不会输出。最多不能超过 5 个字符串,每个字符串不得超过 32 字节 - /// 默认 null - /// - public List? stop { get; set; } - /// - /// 是否流式返回 - /// false - /// - public bool stream { get; set; } = false; - - - } - - - public class PermissionItem - { - /// - /// - /// - public int created { get; set; } - /// - /// - /// - public string id { get; set; } - /// - /// - /// - public string @object { get; set; } - /// - /// - /// - public string allow_create_engine { get; set; } - /// - /// - /// - public string allow_sampling { get; set; } - /// - /// - /// - public string allow_logprobs { get; set; } - /// - /// - /// - public string allow_search_indices { get; set; } - /// - /// - /// - public string allow_view { get; set; } - /// - /// - /// - public string allow_fine_tuning { get; set; } - /// - /// - /// - public string organization { get; set; } - /// - /// - /// - public string @group { get; set; } - /// - /// - /// - public string is_blocking { get; set; } - } - - - public class ChatResError - { - /// - /// 错误信息 - /// - public string message { get; set; } = string.Empty; - /// - /// 错误类型 - /// - public string type { get; set; } = string.Empty; - - } - public class ChatResSSE - { - public string id { get; set; } - public int created { get; set; } - /// - /// 模型id - /// - public string model { get; set; } - /// - /// 对话 - /// - public ChoiceSSE[] choices { get; set; } - } - public class ChatRes - { - public ChatResError? error { get; set; } - public string id { get; set; } - public int created { get; set; } - /// - /// 模型id - /// - public string model { get; set; } - /// - /// 对话 - /// - public Choice[] choices { get; set; } - /// - /// token使用情况 - /// - public Usage usage { get; set; } - } - /// - /// token使用情况 - /// - public class Usage - { - /// - /// 输入token数量 - /// - public int prompt_tokens { get; set; } - /// - /// 返回token数量 - /// - public int completion_tokens { get; set; } - /// - /// 总计token数量 - /// - public int total_tokens { get; set; } - } - - public class ChoiceSSE - { - public int index { get; set; } - public Message delta { get; set; } - public string finish_reason { get; set; } - /// - /// token使用情况 - /// - public Usage usage { get; set; } - } - public class Choice - { - public int index { get; set; } - public Message message { get; set; } - public string finish_reason { get; set; } - } - - public class Message - { - public string role { get; set; } - public string content { get; set; } - } - - public class ModelInfo - { - /// - /// - /// - public int created { get; set; } - /// - /// - /// - public string id { get; set; } - /// - /// - /// - public string @object { get; set; } - /// - /// - /// - public string owned_by { get; set; } - /// - /// - /// - public List permission { get; set; } - /// - /// - /// - public string root { get; set; } - /// - /// - /// - public string parent { get; set; } - } - - public class ModelListResp - { - /// - /// - /// - public string @object { get; set; } - /// - /// - /// - public List data { get; set; } - } - - - public class FileListResp - { - /// - /// - /// - public string @object { get; set; } - /// - /// - /// - public List data { get; set; } - } - - public class FileContent - { - /// - /// - /// - public string content { get; set; } - /// - /// - /// - public string file_type { get; set; } - /// - /// - /// - public string filename { get; set; } - /// - /// - /// - public string title { get; set; } - /// - /// - /// - public string type { get; set; } - } - - - public class FileItem - { - /// - /// - /// - public string id { get; set; } - /// - /// - /// - public string @object { get; set; } - /// - /// - /// - public int bytes { get; set; } - /// - /// - /// - public int created_at { get; set; } - /// - /// - /// - public string filename { get; set; } - /// - /// - /// - public string purpose { get; set; } - /// - /// - /// - public string status { get; set; } - /// - /// - /// - public string status_details { get; set; } - } - - - - public class ErrorMsg - { - /// - /// - /// - public string message { get; set; } - /// - /// - /// - public string type { get; set; } - } - - public class ErrorResponse - { - /// - /// - /// - public ErrorMsg error { get; set; } - } - - -} diff --git a/VideoAnalysisCore/Common/AppCommon.cs b/VideoAnalysisCore/Common/AppCommon.cs index 0d89373..638c802 100644 --- a/VideoAnalysisCore/Common/AppCommon.cs +++ b/VideoAnalysisCore/Common/AppCommon.cs @@ -1,5 +1,6 @@ using FreeRedis; using Microsoft.Extensions.DependencyModel; +using Microsoft.IdentityModel.Tokens; using SqlSugar; using SqlSugar.IOC; using System.Collections; @@ -250,6 +251,8 @@ namespace VideoAnalysisCore.Common { try { + if(value is null || string.IsNullOrEmpty(value.ToString())) + return null; if (Enum.TryParse(value.ToString(), true, out var result) && Enum.IsDefined(typeof(T), result)) return result; return null; diff --git a/VideoAnalysisCore/Common/RedisExpand.cs b/VideoAnalysisCore/Common/RedisExpand.cs index b1be694..e883e0a 100644 --- a/VideoAnalysisCore/Common/RedisExpand.cs +++ b/VideoAnalysisCore/Common/RedisExpand.cs @@ -79,11 +79,12 @@ namespace VideoAnalysisCore.Common /// public static class RedisExpand { + /// /// redis 连接 /// public static RedisClient Redis = new RedisClient(AppCommon.Config.Redis.ConnectionString); - public static Dictionary> SubscribeList = new Dictionary>(); + public static Dictionary> SubscribeList = new Dictionary>(); /// /// 队列池 /// @@ -159,23 +160,25 @@ namespace VideoAnalysisCore.Common var startTime = Redis.HMGet>(RedisExpandKey.Task(taskId), "StartTime").FirstOrDefault(); if (startTime is null) startTime = new Dictionary(); - if (!startTime.ContainsKey(@enum)) - startTime.Add(@enum, DateTime.Now); - else - startTime[@enum] = DateTime.Now; - - Redis.HMSet(RedisExpandKey.Task(taskId), "StartTime", startTime); - if (!SubscribeList.ContainsKey(@enum)) throw new Exception(@enum + " 未实现"); var tId = taskId.ToString(); try { - - while (@enum.NextEnum() != null) + while (true) { - SubscribeList[@enum].Invoke(tId); - @enum = @enum.NextEnum().Value; + if (!startTime.ContainsKey(@enum)) + startTime.Add(@enum, DateTime.Now); + else + startTime[@enum] = DateTime.Now; + + Redis.HMSet(RedisExpandKey.Task(taskId), "StartTime", startTime); + + await SubscribeList[@enum](tId); + var e = @enum.NextEnum(); + if (e is null) + break; + @enum = e.Value; } } catch (Exception ex) @@ -231,7 +234,7 @@ namespace VideoAnalysisCore.Common if (Redis is null) throw new Exception("redis未初始化"); SubscribeList.Add(RedisChannelEnum.下载文件, - (msg) => TouchChannel(RedisChannelEnum.下载文件, msg, + async (msg) => await TouchChannel(RedisChannelEnum.下载文件, msg, (task) => { using var scope = AppCommon.Services?.CreateScope(); @@ -241,13 +244,13 @@ namespace VideoAnalysisCore.Common return scope.ServiceProvider.GetService()?.RunTask(task) ?? Task.CompletedTask; })); SubscribeList.Add(RedisChannelEnum.分离音频, - (msg) => TouchChannel(RedisChannelEnum.分离音频, msg, FFMPGEHandle.RunAsync)); + async (msg) => await TouchChannel(RedisChannelEnum.分离音频, msg, FFMPGEHandle.RunAsync)); SubscribeList.Add(RedisChannelEnum.解析字幕, - (msg) => TouchChannel(RedisChannelEnum.解析字幕, msg, SenseVoice.RunTask)); - SubscribeList.Add(RedisChannelEnum.解析说话人, - (msg) => TouchChannel(RedisChannelEnum.解析说话人, msg, Speaker.Run)); + async (msg) => await TouchChannel(RedisChannelEnum.解析字幕, msg, SenseVoice.RunTask)); + //SubscribeList.Add(RedisChannelEnum.解析说话人, + // async (msg) => await TouchChannel(RedisChannelEnum.解析说话人, msg, Speaker.Run)); SubscribeList.Add(RedisChannelEnum.AI模型分析, - (msg) => TouchChannel(RedisChannelEnum.AI模型分析, msg, + async (msg) => await TouchChannel(RedisChannelEnum.AI模型分析, msg, (task) => { using var scope = AppCommon.Services?.CreateScope(); @@ -256,8 +259,18 @@ namespace VideoAnalysisCore.Common else return scope.ServiceProvider.GetService()?.GetKnow(task) ?? Task.CompletedTask; })); + 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()?.GetVideoQuestion(task) ?? Task.CompletedTask; + })); SubscribeList.Add(RedisChannelEnum.结束任务, - (msg) => TouchChannel(RedisChannelEnum.结束任务, msg, TaskEnd)); + async (msg) => await TouchChannel(RedisChannelEnum.结束任务, msg, TaskEnd)); ReceivingTaskAsync(); @@ -285,12 +298,6 @@ namespace VideoAnalysisCore.Common } Task.Run(async () => { - //todo 项目接收任务进程池 - //接收任务加入池 - //重试任务加入池 - //失败任务删除池 - //停止任务删除池 - //重启项目运行池内所有可用任务 var oldTask = await Redis.GetAsync(RedisExpandKey.IDTask); if (!string.IsNullOrEmpty(oldTask)) { @@ -338,12 +345,17 @@ namespace VideoAnalysisCore.Common return await SetTaskError(taskID, error); } /// - /// 清楚 任务的错误信息 + /// 清除 任务的错误信息 + /// + /// + /// + public static async Task ClearTaskError(long taskID) =>await SetTaskError(taskID, string.Empty); + /// + /// 修改任务的错误信息 /// /// /// /// - public static async Task ClearTaskError(long taskID) =>await SetTaskError(taskID, string.Empty); public static async Task SetTaskError(long taskID, string? error) { Redis.HMSet(RedisExpandKey.Task(taskID), "ErrorMessage", error); @@ -359,14 +371,14 @@ namespace VideoAnalysisCore.Common /// /// /// - public static async void TouchChannel(RedisChannelEnum key, string taskId, Func action = null) + public static async Task TouchChannel(RedisChannelEnum key, string taskId, Func action = null) { if (taskId is null) return; var tID = long.Parse(taskId); if (action is not null) { - var errArr = new Exception[3]; - for (int i = 0; i < 3; i++) + var tryCount = 1; + for (int i = 0; i < tryCount; i++) { Console.WriteLine(DateTime.Now.ToString("HH:mm:ss") + "-> 开始执行 " + key + " " + taskId); try @@ -386,16 +398,16 @@ namespace VideoAnalysisCore.Common } catch (Exception ex) { - errArr[i] = ex; Console.WriteLine("====================[出现异常]===================="); Console.WriteLine(ex.Message); Console.WriteLine(ex.StackTrace); Console.WriteLine("=============================================="); Thread.Sleep(1000); Console.WriteLine(DateTime.Now.ToString("HH:mm:ss") + "-> 稍后后重试." + key + " " + taskId); + if (i+1== tryCount) + throw; } } - throw errArr.Last(); } else { diff --git a/VideoAnalysisCore/Job/TaskFileClearJob.cs b/VideoAnalysisCore/Job/TaskFileClearJob.cs index 6cfeada..4e6da3f 100644 --- a/VideoAnalysisCore/Job/TaskFileClearJob.cs +++ b/VideoAnalysisCore/Job/TaskFileClearJob.cs @@ -41,7 +41,7 @@ namespace VideoAnalysisCore.Job // 查询 2 天前任务执行完成的记录 var completedTasks = videotaskDB.AsQueryable() .Where(t => - t.LastEnum == Model.Enum.RedisChannelEnum.EndTask + t.LastEnum == Model.Enum.RedisChannelEnum.结束任务 && t.EndTime < twoDaysAgo && t.EndTime > endDaysAgo) .ToList(); diff --git a/VideoAnalysisCore/Model/Enum/RedisChannelEnum.cs b/VideoAnalysisCore/Model/Enum/RedisChannelEnum.cs index 455eef5..00548af 100644 --- a/VideoAnalysisCore/Model/Enum/RedisChannelEnum.cs +++ b/VideoAnalysisCore/Model/Enum/RedisChannelEnum.cs @@ -21,10 +21,10 @@ /// 解析字幕 /// 解析字幕 = 20, - /// - /// 解析说话人 - /// - 解析说话人 = 30, + ///// + ///// 解析说话人 + ///// + //解析说话人 = 30, /// /// Chat模型分析 ///