From d12839be2029189826867518fece5839349dec77 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, 23 Jun 2025 17:13:45 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20=E8=AF=BE=E7=A8=8B?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E6=97=A0=E6=95=88=E6=97=B6=E5=AF=BC=E8=87=B4?= =?UTF-8?q?=E7=9A=84=E5=BC=82=E5=B8=B8=20=E6=96=B0=E5=A2=9E=20ToJson?= =?UTF-8?q?=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AICore/FFMPGE/FFMPGEHandle.cs | 2 +- .../AICore/GPT/ChatGPT/ChatGPTClient.cs | 45 +------ .../AICore/GPT/DeepSeek/DeepSeekClient.cs | 6 +- .../AICore/GPT/DeepSeek/DeepSeek_GPT.cs | 118 +++++++++++------- .../AICore/SherpaOnnx/SenseVoice.cs | 2 +- .../AICore/SherpaOnnx/Speaker.cs | 2 +- VideoAnalysisCore/Common/AppCommon.cs | 44 ++++--- VideoAnalysisCore/Common/ExceptionFilter.cs | 2 +- .../Common/Expand/SimpLetexExpand.cs | 2 +- .../Controllers/LJZK_Controller.cs | 2 +- VideoAnalysisCore/Job/NodePackageJob.cs | 2 +- 11 files changed, 114 insertions(+), 113 deletions(-) diff --git a/VideoAnalysisCore/AICore/FFMPGE/FFMPGEHandle.cs b/VideoAnalysisCore/AICore/FFMPGE/FFMPGEHandle.cs index fafcf21..c907e64 100644 --- a/VideoAnalysisCore/AICore/FFMPGE/FFMPGEHandle.cs +++ b/VideoAnalysisCore/AICore/FFMPGE/FFMPGEHandle.cs @@ -101,7 +101,7 @@ namespace VideoAnalysisCore.AICore.FFMPGE keyFrames[i] = -1; } //写入数据库 - var keyFramStr = JsonSerializer.Serialize(keyFrames.Where(s=>s!=-1)); + var keyFramStr = keyFrames.Where(s => s != -1).ToJson(); await DbScoped.Sugar .Updateable() .SetColumns(it => it.PPTKeyFrame == keyFramStr) diff --git a/VideoAnalysisCore/AICore/GPT/ChatGPT/ChatGPTClient.cs b/VideoAnalysisCore/AICore/GPT/ChatGPT/ChatGPTClient.cs index 67aff13..e6b3662 100644 --- a/VideoAnalysisCore/AICore/GPT/ChatGPT/ChatGPTClient.cs +++ b/VideoAnalysisCore/AICore/GPT/ChatGPT/ChatGPTClient.cs @@ -32,47 +32,6 @@ namespace VideoAnalysisCore.AICore.GPT.ChatGPT public async Task<(Usage u, string res)?> ChatSSE(ChatRequest chatReq) { throw new Exception($"未实现"); - //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(); - ChatRes lastChat = new ChatRes(); - - //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; } /// @@ -82,14 +41,14 @@ namespace VideoAnalysisCore.AICore.GPT.ChatGPT /// Return HttpResponseMessage for SSE public async Task<(Usage u, string res)?> Chat(ChatRequest chatReq) { - var requestBody = System.Text.Json.JsonSerializer.Serialize(chatReq); + var requestBody = chatReq.ToJson(); 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($" ChatGPT模型返回异常 返回参数: " + - $" {System.Text.Json.JsonSerializer.Serialize(res)}"); + $" {res?.ToJson()}"); if (string.IsNullOrEmpty(chatResContent)) return null; diff --git a/VideoAnalysisCore/AICore/GPT/DeepSeek/DeepSeekClient.cs b/VideoAnalysisCore/AICore/GPT/DeepSeek/DeepSeekClient.cs index 4bbfbde..cb345f6 100644 --- a/VideoAnalysisCore/AICore/GPT/DeepSeek/DeepSeekClient.cs +++ b/VideoAnalysisCore/AICore/GPT/DeepSeek/DeepSeekClient.cs @@ -50,7 +50,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek //chatReq.model = "deepseek-r1"; if (chatReq.stream) return await ChatSSE(chatReq); postStar: - var requestBody = System.Text.Json.JsonSerializer.Serialize(chatReq); + var requestBody = chatReq.ToJson(); HttpResponseMessage chatResp = PostJsonStream(Path, requestBody); var res1 = await chatResp.Content.ReadAsStringAsync(); if (res1 == null || string.IsNullOrEmpty(res1)|| !chatResp.IsSuccessStatusCode) @@ -65,7 +65,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek var res = await chatResp.Content.ReadFromJsonAsync(); if (res is null || res.error != null) throw new Exception($" GPT模型返回异常 返回参数: " + - $" {System.Text.Json.JsonSerializer.Serialize(res)}"); + $" {res.ToJson()}"); var d = thinkMSG(res?.choices.FirstOrDefault()?.message); var chatResContent = d.m1; var chatResReasoning = d.m2; @@ -136,7 +136,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek /// Return HttpResponseMessage for SSE public async Task<(Usage u, string res, string reasoning)?> ChatSSE(ChatRequest chatReq) { - var requestBody = System.Text.Json.JsonSerializer.Serialize(chatReq); + var requestBody = chatReq.ToJson(); PostJsonStream: var chatResp = PostJsonStream(string.Empty, requestBody); if (!chatResp.IsSuccessStatusCode) diff --git a/VideoAnalysisCore/AICore/GPT/DeepSeek/DeepSeek_GPT.cs b/VideoAnalysisCore/AICore/GPT/DeepSeek/DeepSeek_GPT.cs index abf2623..f20e29b 100644 --- a/VideoAnalysisCore/AICore/GPT/DeepSeek/DeepSeek_GPT.cs +++ b/VideoAnalysisCore/AICore/GPT/DeepSeek/DeepSeek_GPT.cs @@ -58,7 +58,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek /// 获取内容对应的章节 /// /// - private async Task> GetVideoKnow(List questionRes, VideoTask taskInfo, + private async Task> GetVideoKnow(VideoKnowRes[] questionRes, VideoTask taskInfo, string sections, List knowledgeInfos) { var knows = string.Join(',', knowledgeInfos.Select(s => s.Id + "|" + s.Name)); @@ -67,8 +67,8 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek .GroupBy(s => s.Name) .ToDictionary(s => s.First().Name, s => s.First().Id); questionRes = questionRes.Where(s => s != null) - .OrderBy(s => s.StartTime).ToList(); - var thems = JsonSerializer.Serialize(questionRes.Adapt());// string.Join(',', questionRes.Select(s => s.StartTime + "->" + s.Theme)); + .OrderBy(s => s.StartTime).ToArray(); + var thems = questionRes.Adapt().ToJson(); var checkResFormat1 = """[{"StartTime":开始秒(number),"KnowPoint":知识点名称(string),"KnowPointId":知识点Id(string)}]"""; var knowMessages = $"我针对{taskInfo.Subject}课堂授课视频分析出了视频的授课阶段片段。" + @@ -94,7 +94,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek s => { var ks = s.KnowPoint.Split(",").Distinct(); - var StageId=Yitter.IdGenerator.YitIdHelper.NextId(); + var StageId = Yitter.IdGenerator.YitIdHelper.NextId(); return ks.Where(x => knowDic.ContainsKey(x)) .Select(x => new VideoKonwPoint() { @@ -160,11 +160,11 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek /// 检查AI切片结果质量 /// /// - private async Task VerifySpanQuality(List questionRes, VideoTask taskInfo, TotalCaptionsDto captions, string sections, int course_Id) + private async Task VerifySpanQuality(VideoKnowRes[] questionRes, VideoTask taskInfo, TotalCaptionsDto captions, string sections, int course_Id) { //校验结果质量 - var thems = JsonSerializer.Serialize(questionRes.Adapt()); - var pptFormat = taskInfo.VideoType==AttachmentsInfoType.复习 + var thems = questionRes.Adapt().ToJson(); + var pptFormat = taskInfo.VideoType == AttachmentsInfoType.复习 ? "这堂课是习题课,所讲解内容都是试题。" : string.Empty; var checkResFormat = """{"Score":打分(number),"Evaluation":评价(string)""";//,"Data":优化后的分段(array)}"""; @@ -206,7 +206,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek .Take(spanCount); if (cArr.Count() == 0) return; - var nowCaptionStr =JsonSerializer.Serialize(cArr.Select(s =>s.Text)); + var nowCaptionStr = cArr.Select(s => s.Text).ToJson(); var resFormat = """[string(修改结果)]"""; var postMessages = $"这是一堂中国{subject}课堂的字幕,由结果是语音识别提供。" + @@ -219,11 +219,11 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek $"`{nowCaptionStr}`" + $"字幕结束。" + $"最后请确保输出字幕条数与输入字幕条数一致!!! 如果不一致则重新优化并且确保字幕条数一致!!!!"; - Console.WriteLine(DateTime.Now + $"=>字幕优化 分段{s}/{totalCount}开始..."); - var resData = await ChatAsync(taskInfo.Id.ToString(), postMessages, "优化字幕", "deepseek-chat"); + Console.WriteLine(DateTime.Now + $"=>{taskInfo.Id}字幕优化 分段{s}开始..."); + var resData = await ChatAsync(taskInfo.Id.ToString(), postMessages, "优化字幕", "deepseek-chat", 3000); if (resData.Count() != cArr.Count()) { - Console.WriteLine(DateTime.Now + $"=>字幕优化 分段{s}/{totalCount} AI结果数量不匹配,重试"); + Console.WriteLine(DateTime.Now + $"=>{taskInfo.Id}字幕优化 分段{s} AI结果数量不匹配,重试×"); continue; } newCaptionsList.AddRange(resData.Select((text, i) => new SenseVoiceRes() @@ -232,13 +232,13 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek End = captionsArr[spanCount * s + i].End, Text = text, })); - Console.WriteLine(DateTime.Now + $"=>字幕优化 分段{s}/{totalCount}完成√"); + Console.WriteLine(DateTime.Now + $"=>{taskInfo.Id}字幕优化 分段{s}完成√ "); return; } }); var res = newCaptionsList.OrderBy(s => s.Start).ToArray(); Console.WriteLine(DateTime.Now + $"=>字幕优化执行完成"); - var jsonData = JsonSerializer.Serialize(res); + var jsonData = res.ToJson(); await videoTaskDB.AsUpdateable() .SetColumns(it => it.CaptionsAI == jsonData) .Where(it => it.Id == taskInfo.Id) @@ -250,11 +250,11 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek /// 视频AI分析字幕 /// /// - private async Task Analytics(List questionRes, VideoTask taskInfo, + private async Task Analytics(VideoTask taskInfo, TotalCaptionsDto captions, string sections) { var tryCount = 10; - while (tryCount-->0) + while (tryCount-- > 0) { try { @@ -300,15 +300,12 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek break; case AttachmentsInfoType.活动: case AttachmentsInfoType.班会: - throw new Exception("无效的课程类型"); default: - break; + throw new Exception("无效的课程类型"); } Console.WriteLine(DateTime.Now + $"=>{taskInfo.Id.ToString()}.开始分析视频内容 {tryCount}"); - var resData = await ChatAsync(taskInfo.Id.ToString(), postMessages, "分析字幕"); - questionRes.AddRange(resData); - break; + return await ChatAsync(taskInfo.Id.ToString(), postMessages, "分析字幕"); } catch (Exception ex) { @@ -317,10 +314,21 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek Console.WriteLine(DateTime.Now + ex.StackTrace); } } + return null; } - - public async Task ChatAsync(string task, string postMessages, string title, string model = "deepseek-reasoner") + /// + /// + /// + /// 返回JSON类型 + /// 任务id + /// 提示词 + /// 任务类型 + /// GPT版本 + /// 最大token 不设置默认最大值 16000/8000 + /// + /// + public async Task ChatAsync(string task, string postMessages, string title, string model = "deepseek-reasoner", int max_tokens = -1) { Message[] messageArr = [ new Message(postMessages,"user"), @@ -330,24 +338,27 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek { taskId = task, model = model, - max_tokens= model== "deepseek-reasoner"?16000:8000, + max_tokens = model == "deepseek-reasoner" ? 16000 : 8000, stream = true, temperature = 0.2f, messages = messageArr }; + if (max_tokens != -1) + chatRep.max_tokens = max_tokens; var tryCount = 10; while (--tryCount > 0) { try { - var time = title+DateTime.Now.ToString("MMddHHmmss"); + var time = title + DateTime.Now.ToString("MMddHHmmss"); var redisCached = new object[2] { chatRep, null }; - RedisExpand.SetTaskGPTCached(task, time,chatRep); + RedisExpand.SetTaskGPTCached(task, time, chatRep); var chatResp = await chatClient.Chat(chatRep); var chatResContent = chatResp?.res; if (string.IsNullOrEmpty(chatResContent)) throw new Exception("GPT返回message无效结果"); - if (chatResp != null) { + if (chatResp != null) + { redisCached[1] = new object[] { chatResp.Value.res, chatResp.Value.u, chatResp.Value.reasoning }; RedisExpand.SetTaskGPTCached(task, time, redisCached); } @@ -359,6 +370,8 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek chatResContent = chatResContent?.Replace("}|{", "},{"); chatResContent = chatResContent?.Trim(); + if (string.IsNullOrEmpty(chatResContent)) + throw new Exception("ChatGPT返回结果无有效JSON"); var startsStr = typeof(T).IsArray ? "[" : "{"; var endStr = typeof(T).IsArray ? "]" : "}"; if (!chatResContent.StartsWith(startsStr)) @@ -404,17 +417,17 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek var videoKnowDic = knowledgeInfos .GroupBy(s => s.Id) .ToDictionary(s => s.Key, s => s.First()); - var insertData =new List(); - var insertQuestionKonw = new List(); + var insertData = new List(); + var insertQuestionKonw = new List(); foreach (var item in farmeArr) { var knowInfoArr = videoKnowArr - .Where(s => item+20 >= s.StartTime && item <= s.EndTime) + .Where(s => item + 20 >= s.StartTime && item <= s.EndTime) .ToArray(); - if (knowInfoArr is null || knowInfoArr.Count() ==0) + if (knowInfoArr is null || knowInfoArr.Count() == 0) continue; var tryCount = 50; - while (tryCount>1) + while (tryCount > 1) { tryCount--; try @@ -424,10 +437,10 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek .ProcessImageAsync(new SimpleTexOcrRequest(filePath)); if (!sRes.Success) continue; - if(sRes.Result.res.value.Trim().Length<10)//总试题内容长度小于10 视为无效题目 + if (sRes.Result.res.value.Trim().Length < 10)//总试题内容长度小于10 视为无效题目 break; Console.WriteLine(DateTime.Now + $"=>{taskInfo.Id} 提取{knowInfoArr.First().StartTime}秒试题的试题内容"); - Console.WriteLine( sRes.Result.res.value); + Console.WriteLine(sRes.Result.res.value); //var knowArr=JsonSerializer.Serialize(knowInfoArr.Select(s => new { s.KnowPointId, s.KnowPoint })); var resFormat = """[{"Type":string(试题类型),"TopicStem":string(试题题干),"QuestionArr":[{"Question":string(子问题),"KnowPointId":(string)知识点ID}]}]"""; var postMessages = @@ -444,7 +457,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek $"`{sRes.Result.res.value}`"; var resData = await ChatAsync(taskInfo.Id.ToString(), postMessages, "提取试题", "deepseek-chat"); //var resData = await ChatAsync(taskInfo.Id.ToString(), postMessages, "提取试题"); - if(resData is null || resData.Count()==0) + if (resData is null || resData.Count() == 0) break; foreach (var q in resData) { @@ -460,13 +473,13 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek vq.Question = qt.Question; vq.TopicId = TopicId; vq.Type = q.Type; - if(string.IsNullOrEmpty(qt.KnowPointId)) + if (string.IsNullOrEmpty(qt.KnowPointId)) continue;//重试 insertData.Add(vq); foreach (var kid in qt.KnowPointId.Split(",")) { - var tryOk = int.TryParse(kid.Split("|").First(),out int kidd); - if(!tryOk || !videoKnowDic.ContainsKey(kidd)) + var tryOk = int.TryParse(kid.Split("|").First(), out int kidd); + if (!tryOk || !videoKnowDic.ContainsKey(kidd)) continue;//跳过未识别知识点 insertQuestionKonw.Add(new VideoQuestionKonw() { @@ -491,7 +504,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek ossClient.AddVideoQuestionUrl(insertData); await videoQuestionDB.AsDeleteable() - .Where(s=>s.VideoTaskId== taskInfo.Id) + .Where(s => s.VideoTaskId == taskInfo.Id) .ExecuteCommandAsync(); await videoQuestionKonwDB.AsDeleteable() .Where(s => s.VideoTaskId == taskInfo.Id) @@ -525,7 +538,17 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek Course_Id = 27; break; } - + switch (taskInfo?.VideoType) + { + case AttachmentsInfoType.其他资料: + case AttachmentsInfoType.新课: + case AttachmentsInfoType.复习: + break; + case AttachmentsInfoType.活动: + case AttachmentsInfoType.班会: + default: + throw new Exception("无效的课程类型"); + } var captionsArr = JsonSerializer.Deserialize(taskInfo.Captions); //处理视频授课章节 @@ -543,16 +566,16 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek //合并字幕 var captions = ExpandFunction.GetSpeakerCaptions(captionsArr); var maxVideoTime = captions?.TimeBase?.LastOrDefault()?.End ?? 0; - var questionRes = new List(); - while (true) + VideoKnowRes[]? questionRes =null; + var tryCount = 20; + while (tryCount-- > 0) { - questionRes = new List(); //视频字幕分析 - await Analytics(questionRes, taskInfo, captions, sections); + questionRes = await Analytics(taskInfo, captions, sections); - if (questionRes.Count == 0) continue; + if (questionRes is null) continue; //处理分段 知识点 - var insertData = await GetVideoKnow(questionRes, taskInfo, sections, knowledgeInfos); + var insertData = await GetVideoKnow(questionRes, taskInfo, sections, knowledgeInfos); //校验结果质量 var checkRes = await VerifySpanQuality(questionRes, taskInfo, captions, sections, Course_Id); @@ -575,7 +598,10 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek continue; } } - + if (tryCount == 0) + { + throw new Exception("重试次数过多!"); + } await RedisExpand.Redis .HMSetAsync(RedisExpandKey.Task(task), "VideoKnows", questionRes); diff --git a/VideoAnalysisCore/AICore/SherpaOnnx/SenseVoice.cs b/VideoAnalysisCore/AICore/SherpaOnnx/SenseVoice.cs index 462c469..ffda138 100644 --- a/VideoAnalysisCore/AICore/SherpaOnnx/SenseVoice.cs +++ b/VideoAnalysisCore/AICore/SherpaOnnx/SenseVoice.cs @@ -172,7 +172,7 @@ namespace VideoAnalysisCore.AICore.SherpaOnnx if (!string.IsNullOrEmpty(task)) { Console.WriteLine(DateTime.Now + "=> SenseVoice 字幕数量" + res.Count); - var captionsStr = JsonSerializer.Serialize(res); + var captionsStr = res.ToJson(); await DbScoped.Sugar .Updateable() .SetColumns(it => it.Captions == captionsStr) diff --git a/VideoAnalysisCore/AICore/SherpaOnnx/Speaker.cs b/VideoAnalysisCore/AICore/SherpaOnnx/Speaker.cs index 098ec78..81b0b1c 100644 --- a/VideoAnalysisCore/AICore/SherpaOnnx/Speaker.cs +++ b/VideoAnalysisCore/AICore/SherpaOnnx/Speaker.cs @@ -78,7 +78,7 @@ namespace VideoAnalysisCore.AICore.SherpaOnnx }, nint.Zero); var res = segments.Select(s => new OfflineSpeakerRes(s)); await RedisExpand.Redis.HSetAsync(RedisExpandKey.Task(task), "Speaker", res); - var speakerStr = JsonSerializer.Serialize(res); + var speakerStr = res.ToJson(); await DbScoped.Sugar .Updateable() .SetColumns(it => it.Speaker == speakerStr) diff --git a/VideoAnalysisCore/Common/AppCommon.cs b/VideoAnalysisCore/Common/AppCommon.cs index 638c802..1859849 100644 --- a/VideoAnalysisCore/Common/AppCommon.cs +++ b/VideoAnalysisCore/Common/AppCommon.cs @@ -52,7 +52,6 @@ namespace VideoAnalysisCore.Common throw; } } - /// /// 程序配置 /// @@ -83,8 +82,9 @@ namespace VideoAnalysisCore.Common /// /// 拓展函数 /// - public static class ExpandFunction + public static class ExpandFunction { + static Dictionary FormulaData; static string FormulaDataKey; /// @@ -92,15 +92,31 @@ namespace VideoAnalysisCore.Common /// public static string FrameName = "frame_"; + /// + /// 对象转化为JSON字符串 + /// + /// 拓展对象 + /// 美化输出? + /// + public static string ToJson(this object o, bool WriteIndented = false) + { + var jsonOptions = new JsonSerializerOptions + { + Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping, + WriteIndented = WriteIndented // 如果需要美化输出 + }; + return JsonSerializer.Serialize(o, jsonOptions); + } + /// /// 获取视频帧文件资源路径 /// /// /// 帧文件 对应的时间轴 /// - public static string FramePath(this VideoTask task, int fTime) + public static string FramePath(this VideoTask task, int fTime) { - return Path.Combine(task.Id.ToString().LocalPath(), $"{FrameName}{(fTime / 5).ToString().PadLeft(3,'0')}.jpg"); + return Path.Combine(task.Id.ToString().LocalPath(), $"{FrameName}{(fTime / 5).ToString().PadLeft(3, '0')}.jpg"); } /// @@ -110,10 +126,10 @@ namespace VideoAnalysisCore.Common /// public static string HandleFormula(string f) { - if (FormulaData is null) + if (FormulaData is null) { var hotwords = JsonSerializer.Deserialize(File.ReadAllText(Path.Combine(AppCommon.AIModelFile, "Hotwords.json"))); - foreach (var item in hotwords.OrderByDescending(s=>s.key.Count())) + foreach (var item in hotwords.OrderByDescending(s => s.key.Count())) foreach (var key in item.v) FormulaData.Add(key, item.key); } @@ -121,7 +137,7 @@ namespace VideoAnalysisCore.Common FormulaDataKey = string.Join("|", FormulaData.Keys.Count); if (string.IsNullOrEmpty(f)) return f; - return Regex.Replace(f, FormulaDataKey, + return Regex.Replace(f, FormulaDataKey, match => FormulaData[match.Value] ); @@ -152,7 +168,7 @@ namespace VideoAnalysisCore.Common /// /// 获取Task处理后的 说话人字幕 /// - public static TotalCaptionsDto GetSpeakerCaptions(SenseVoiceRes[] captionsArr, OfflineSpeakerRes[]? speakerArr=null) + public static TotalCaptionsDto GetSpeakerCaptions(SenseVoiceRes[] captionsArr, OfflineSpeakerRes[]? speakerArr = null) { if (captionsArr is null || captionsArr.Length == 0) //|| speakerArr is null || speakerArr.Length == 0) @@ -160,15 +176,15 @@ namespace VideoAnalysisCore.Common // 教师说话人Id var techerId = speakerArr is null || !speakerArr.Any() ? 0 - :speakerArr.GroupBy(s=>s.SpeakerIndex).Select(s => (s.Key,s.Sum(x=>x.Total))) - .OrderByDescending(s=>s.Item2).First().Key; + : speakerArr.GroupBy(s => s.SpeakerIndex).Select(s => (s.Key, s.Sum(x => x.Total))) + .OrderByDescending(s => s.Item2).First().Key; var teacherSpeaking = 0f; var studentSpeaking = 0f; var results = new Dictionary>(); var ss = new List { 1 }; if (speakerArr is null || speakerArr.Count() == 0) { - results = captionsArr.ToDictionary(s => s, s=> ss); + results = captionsArr.ToDictionary(s => s, s => ss); } else { @@ -213,12 +229,12 @@ namespace VideoAnalysisCore.Common StudentSpeaking = (decimal)studentSpeaking, TeacherSpeaking = (decimal)teacherSpeaking, Captions = stringBuilder.ToString(), - TimeBase = results.Select(s=>new TimeBase() + TimeBase = results.Select(s => new TimeBase() { Start = s.Key.Start, End = s.Key.End, Content = s.Key.Text, - TimeBaseType = s.Value.Count == 1 && s.Value.First() == techerId + TimeBaseType = s.Value.Count == 1 && s.Value.First() == techerId ? TimeBaseTypeEnum.教师讲授 : TimeBaseTypeEnum.互动交流 }) @@ -251,7 +267,7 @@ namespace VideoAnalysisCore.Common { try { - if(value is null || string.IsNullOrEmpty(value.ToString())) + 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; diff --git a/VideoAnalysisCore/Common/ExceptionFilter.cs b/VideoAnalysisCore/Common/ExceptionFilter.cs index 2c1622f..9f4cd11 100644 --- a/VideoAnalysisCore/Common/ExceptionFilter.cs +++ b/VideoAnalysisCore/Common/ExceptionFilter.cs @@ -26,7 +26,7 @@ namespace VideoAnalysisCore.Common StackTrace = context.Exception.StackTrace, }; // 将错误对象序列化为JSON格式 - var json = JsonSerializer.Serialize(errorObject); + var json =errorObject.ToJson(); // 设置响应内容类型为JSON context.HttpContext.Response.ContentType = "application/json"; diff --git a/VideoAnalysisCore/Common/Expand/SimpLetexExpand.cs b/VideoAnalysisCore/Common/Expand/SimpLetexExpand.cs index a713638..5a4640a 100644 --- a/VideoAnalysisCore/Common/Expand/SimpLetexExpand.cs +++ b/VideoAnalysisCore/Common/Expand/SimpLetexExpand.cs @@ -128,7 +128,7 @@ namespace VideoAnalysisCore.Common.Expand if (request.isolated_formula_wrapper != null) { - var isolatedWrapper = JsonSerializer.Serialize(request.isolated_formula_wrapper); + var isolatedWrapper = request.isolated_formula_wrapper.ToJson(); content.Add(new StringContent(isolatedWrapper), nameof(request.isolated_formula_wrapper)); parameters[nameof(request.isolated_formula_wrapper)] = isolatedWrapper; } diff --git a/VideoAnalysisCore/Controllers/LJZK_Controller.cs b/VideoAnalysisCore/Controllers/LJZK_Controller.cs index 73a6b55..4483503 100644 --- a/VideoAnalysisCore/Controllers/LJZK_Controller.cs +++ b/VideoAnalysisCore/Controllers/LJZK_Controller.cs @@ -54,7 +54,7 @@ namespace VideoAnalysisCore.Controllers [HttpPost(Name = "NodePackage")] public async Task NodePackage(NodePackageReq[] reqArr) { - Console.WriteLine($"{DateTime.Now} ļ req=" + JsonSerializer.Serialize(reqArr)); + Console.WriteLine($"{DateTime.Now} ļ req=" + reqArr.ToJson()); if (reqArr is null || reqArr.Count() == 0) return BadRequest("ЧƵб"); var videos = new List(reqArr.Count()); diff --git a/VideoAnalysisCore/Job/NodePackageJob.cs b/VideoAnalysisCore/Job/NodePackageJob.cs index e18a84a..75d96b4 100644 --- a/VideoAnalysisCore/Job/NodePackageJob.cs +++ b/VideoAnalysisCore/Job/NodePackageJob.cs @@ -81,7 +81,7 @@ namespace VideoAnalysisCore.Job var request = new HttpRequestMessage(HttpMethod.Post, postUrl); request.Headers.Add("Area", item.Area); // 直接添加到本次请求头 request.Headers.Add("HostIP", item.HostIP); // 直接添加到本次请求头 - request.Content = new StringContent(JsonSerializer.Serialize(postData), Encoding.UTF8, "application/json"); + request.Content = new StringContent(postData.ToJson(), Encoding.UTF8, "application/json"); responseMessage = await apiClent.SendAsync(request); if (responseMessage.IsSuccessStatusCode)