修复 课程类型无效时导致的异常

新增 ToJson函数
This commit is contained in:
小肥羊 2025-06-23 17:13:45 +08:00
parent 73d4fbd8c1
commit d12839be20
11 changed files with 114 additions and 113 deletions

View File

@ -101,7 +101,7 @@ namespace VideoAnalysisCore.AICore.FFMPGE
keyFrames[i] = -1; keyFrames[i] = -1;
} }
//写入数据库 //写入数据库
var keyFramStr = JsonSerializer.Serialize(keyFrames.Where(s=>s!=-1)); var keyFramStr = keyFrames.Where(s => s != -1).ToJson();
await DbScoped.Sugar await DbScoped.Sugar
.Updateable<VideoTask>() .Updateable<VideoTask>()
.SetColumns(it => it.PPTKeyFrame == keyFramStr) .SetColumns(it => it.PPTKeyFrame == keyFramStr)

View File

@ -32,47 +32,6 @@ namespace VideoAnalysisCore.AICore.GPT.ChatGPT
public async Task<(Usage u, string res)?> ChatSSE(ChatRequest chatReq) public async Task<(Usage u, string res)?> ChatSSE(ChatRequest chatReq)
{ {
throw new Exception($"未实现"); 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<ChatRes>(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;
} }
/// <summary> /// <summary>
@ -82,14 +41,14 @@ namespace VideoAnalysisCore.AICore.GPT.ChatGPT
/// <returns>Return HttpResponseMessage for SSE</returns> /// <returns>Return HttpResponseMessage for SSE</returns>
public async Task<(Usage u, string res)?> Chat(ChatRequest chatReq) 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 chatResp = await PostJsonStreamAsync("v1/chat/completions", requestBody);
var res = await chatResp.Content.ReadFromJsonAsync<ChatRes>(); var res = await chatResp.Content.ReadFromJsonAsync<ChatRes>();
var chatResContent = res?.choices.FirstOrDefault()?.message.content.Trim(); var chatResContent = res?.choices.FirstOrDefault()?.message.content.Trim();
if (res is null || res.error != null) if (res is null || res.error != null)
throw new Exception($" ChatGPT模型返回异常 返回参数: " + throw new Exception($" ChatGPT模型返回异常 返回参数: " +
$" {System.Text.Json.JsonSerializer.Serialize(res)}"); $" {res?.ToJson()}");
if (string.IsNullOrEmpty(chatResContent)) if (string.IsNullOrEmpty(chatResContent))
return null; return null;

View File

@ -50,7 +50,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
//chatReq.model = "deepseek-r1"; //chatReq.model = "deepseek-r1";
if (chatReq.stream) return await ChatSSE(chatReq); if (chatReq.stream) return await ChatSSE(chatReq);
postStar: postStar:
var requestBody = System.Text.Json.JsonSerializer.Serialize(chatReq); var requestBody = chatReq.ToJson();
HttpResponseMessage chatResp = PostJsonStream(Path, requestBody); HttpResponseMessage chatResp = PostJsonStream(Path, requestBody);
var res1 = await chatResp.Content.ReadAsStringAsync(); var res1 = await chatResp.Content.ReadAsStringAsync();
if (res1 == null || string.IsNullOrEmpty(res1)|| !chatResp.IsSuccessStatusCode) if (res1 == null || string.IsNullOrEmpty(res1)|| !chatResp.IsSuccessStatusCode)
@ -65,7 +65,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
var res = await chatResp.Content.ReadFromJsonAsync<ChatRes>(); var res = await chatResp.Content.ReadFromJsonAsync<ChatRes>();
if (res is null || res.error != null) if (res is null || res.error != null)
throw new Exception($" GPT模型返回异常 返回参数: " + throw new Exception($" GPT模型返回异常 返回参数: " +
$" {System.Text.Json.JsonSerializer.Serialize(res)}"); $" {res.ToJson()}");
var d = thinkMSG(res?.choices.FirstOrDefault()?.message); var d = thinkMSG(res?.choices.FirstOrDefault()?.message);
var chatResContent = d.m1; var chatResContent = d.m1;
var chatResReasoning = d.m2; var chatResReasoning = d.m2;
@ -136,7 +136,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
/// <returns>Return HttpResponseMessage for SSE</returns> /// <returns>Return HttpResponseMessage for SSE</returns>
public async Task<(Usage u, string res, string reasoning)?> ChatSSE(ChatRequest chatReq) 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: PostJsonStream:
var chatResp = PostJsonStream(string.Empty, requestBody); var chatResp = PostJsonStream(string.Empty, requestBody);
if (!chatResp.IsSuccessStatusCode) if (!chatResp.IsSuccessStatusCode)

View File

@ -58,7 +58,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
/// 获取内容对应的章节 /// 获取内容对应的章节
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
private async Task<List<VideoKonwPoint>> GetVideoKnow(List<VideoKnowRes> questionRes, VideoTask taskInfo, private async Task<List<VideoKonwPoint>> GetVideoKnow(VideoKnowRes[] questionRes, VideoTask taskInfo,
string sections, List<KnowledgeInfo> knowledgeInfos) string sections, List<KnowledgeInfo> knowledgeInfos)
{ {
var knows = string.Join(',', knowledgeInfos.Select(s => s.Id + "|" + s.Name)); var knows = string.Join(',', knowledgeInfos.Select(s => s.Id + "|" + s.Name));
@ -67,8 +67,8 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
.GroupBy(s => s.Name) .GroupBy(s => s.Name)
.ToDictionary(s => s.First().Name, s => s.First().Id); .ToDictionary(s => s.First().Name, s => s.First().Id);
questionRes = questionRes.Where(s => s != null) questionRes = questionRes.Where(s => s != null)
.OrderBy(s => s.StartTime).ToList(); .OrderBy(s => s.StartTime).ToArray();
var thems = JsonSerializer.Serialize(questionRes.Adapt<VideoKnowQueryDto[]>());// string.Join(',', questionRes.Select(s => s.StartTime + "->" + s.Theme)); var thems = questionRes.Adapt<VideoKnowQueryDto[]>().ToJson();
var checkResFormat1 = """[{"StartTime":开始秒(number),"KnowPoint":知识点名称(string),"KnowPointId":知识点Id(string)}]"""; var checkResFormat1 = """[{"StartTime":开始秒(number),"KnowPoint":知识点名称(string),"KnowPointId":知识点Id(string)}]""";
var knowMessages = var knowMessages =
$"我针对{taskInfo.Subject}课堂授课视频分析出了视频的授课阶段片段。" + $"我针对{taskInfo.Subject}课堂授课视频分析出了视频的授课阶段片段。" +
@ -94,7 +94,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
s => s =>
{ {
var ks = s.KnowPoint.Split(",").Distinct(); 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)) return ks.Where(x => knowDic.ContainsKey(x))
.Select(x => new VideoKonwPoint() .Select(x => new VideoKonwPoint()
{ {
@ -160,11 +160,11 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
/// 检查AI切片结果质量 /// 检查AI切片结果质量
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
private async Task<CheckMessageDto> VerifySpanQuality(List<VideoKnowRes> questionRes, VideoTask taskInfo, TotalCaptionsDto captions, string sections, int course_Id) private async Task<CheckMessageDto> VerifySpanQuality(VideoKnowRes[] questionRes, VideoTask taskInfo, TotalCaptionsDto captions, string sections, int course_Id)
{ {
//校验结果质量 //校验结果质量
var thems = JsonSerializer.Serialize(questionRes.Adapt<VideoKnowQueryDto[]>()); var thems = questionRes.Adapt<VideoKnowQueryDto[]>().ToJson();
var pptFormat = taskInfo.VideoType==AttachmentsInfoType. var pptFormat = taskInfo.VideoType == AttachmentsInfoType.
? "这堂课是习题课,所讲解内容都是试题。" ? "这堂课是习题课,所讲解内容都是试题。"
: string.Empty; : string.Empty;
var checkResFormat = """{"Score":打分(number),"Evaluation":评价(string)""";//,"Data":优化后的分段(array)}"""; var checkResFormat = """{"Score":打分(number),"Evaluation":评价(string)""";//,"Data":优化后的分段(array)}""";
@ -206,7 +206,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
.Take(spanCount); .Take(spanCount);
if (cArr.Count() == 0) if (cArr.Count() == 0)
return; return;
var nowCaptionStr =JsonSerializer.Serialize(cArr.Select(s =>s.Text)); var nowCaptionStr = cArr.Select(s => s.Text).ToJson();
var resFormat = """[string(修改结果)]"""; var resFormat = """[string(修改结果)]""";
var postMessages = var postMessages =
$"这是一堂中国{subject}课堂的字幕,由结果是语音识别提供。" + $"这是一堂中国{subject}课堂的字幕,由结果是语音识别提供。" +
@ -219,11 +219,11 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
$"`{nowCaptionStr}`" + $"`{nowCaptionStr}`" +
$"字幕结束。" + $"字幕结束。" +
$"最后请确保输出字幕条数与输入字幕条数一致!!! 如果不一致则重新优化并且确保字幕条数一致!!!!"; $"最后请确保输出字幕条数与输入字幕条数一致!!! 如果不一致则重新优化并且确保字幕条数一致!!!!";
Console.WriteLine(DateTime.Now + $"=>字幕优化 分段{s}/{totalCount}开始..."); Console.WriteLine(DateTime.Now + $"=>{taskInfo.Id}字幕优化 分段{s}开始...");
var resData = await ChatAsync<string[]>(taskInfo.Id.ToString(), postMessages, "优化字幕", "deepseek-chat"); var resData = await ChatAsync<string[]>(taskInfo.Id.ToString(), postMessages, "优化字幕", "deepseek-chat", 3000);
if (resData.Count() != cArr.Count()) if (resData.Count() != cArr.Count())
{ {
Console.WriteLine(DateTime.Now + $"=>字幕优化 分段{s}/{totalCount} AI结果数量不匹配,重试"); Console.WriteLine(DateTime.Now + $"=>{taskInfo.Id}字幕优化 分段{s} AI结果数量不匹配,重试×");
continue; continue;
} }
newCaptionsList.AddRange(resData.Select((text, i) => new SenseVoiceRes() newCaptionsList.AddRange(resData.Select((text, i) => new SenseVoiceRes()
@ -232,13 +232,13 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
End = captionsArr[spanCount * s + i].End, End = captionsArr[spanCount * s + i].End,
Text = text, Text = text,
})); }));
Console.WriteLine(DateTime.Now + $"=>字幕优化 分段{s}/{totalCount}完成√"); Console.WriteLine(DateTime.Now + $"=>{taskInfo.Id}字幕优化 分段{s}完成√ ");
return; return;
} }
}); });
var res = newCaptionsList.OrderBy(s => s.Start).ToArray(); var res = newCaptionsList.OrderBy(s => s.Start).ToArray();
Console.WriteLine(DateTime.Now + $"=>字幕优化执行完成"); Console.WriteLine(DateTime.Now + $"=>字幕优化执行完成");
var jsonData = JsonSerializer.Serialize(res); var jsonData = res.ToJson();
await videoTaskDB.AsUpdateable() await videoTaskDB.AsUpdateable()
.SetColumns(it => it.CaptionsAI == jsonData) .SetColumns(it => it.CaptionsAI == jsonData)
.Where(it => it.Id == taskInfo.Id) .Where(it => it.Id == taskInfo.Id)
@ -250,11 +250,11 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
/// 视频AI分析字幕 /// 视频AI分析字幕
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
private async Task Analytics(List<VideoKnowRes> questionRes, VideoTask taskInfo, private async Task<VideoKnowRes[]> Analytics(VideoTask taskInfo,
TotalCaptionsDto captions, string sections) TotalCaptionsDto captions, string sections)
{ {
var tryCount = 10; var tryCount = 10;
while (tryCount-->0) while (tryCount-- > 0)
{ {
try try
{ {
@ -300,15 +300,12 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
break; break;
case AttachmentsInfoType.: case AttachmentsInfoType.:
case AttachmentsInfoType.: case AttachmentsInfoType.:
throw new Exception("无效的课程类型");
default: default:
break; throw new Exception("无效的课程类型");
} }
Console.WriteLine(DateTime.Now + $"=>{taskInfo.Id.ToString()}.开始分析视频内容 {tryCount}"); Console.WriteLine(DateTime.Now + $"=>{taskInfo.Id.ToString()}.开始分析视频内容 {tryCount}");
var resData = await ChatAsync<VideoKnowRes[]>(taskInfo.Id.ToString(), postMessages, "分析字幕"); return await ChatAsync<VideoKnowRes[]>(taskInfo.Id.ToString(), postMessages, "分析字幕");
questionRes.AddRange(resData);
break;
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -317,10 +314,21 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
Console.WriteLine(DateTime.Now + ex.StackTrace); Console.WriteLine(DateTime.Now + ex.StackTrace);
} }
} }
return null;
} }
/// <summary>
public async Task<T> ChatAsync<T>(string task, string postMessages, string title, string model = "deepseek-reasoner") ///
/// </summary>
/// <typeparam name="T">返回JSON类型</typeparam>
/// <param name="task">任务id</param>
/// <param name="postMessages">提示词</param>
/// <param name="title">任务类型</param>
/// <param name="model">GPT版本</param>
/// <param name="max_tokens">最大token <para>不设置默认最大值 16000/8000</para></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public async Task<T> ChatAsync<T>(string task, string postMessages, string title, string model = "deepseek-reasoner", int max_tokens = -1)
{ {
Message[] messageArr = [ Message[] messageArr = [
new Message(postMessages,"user"), new Message(postMessages,"user"),
@ -330,24 +338,27 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
{ {
taskId = task, taskId = task,
model = model, model = model,
max_tokens= model== "deepseek-reasoner"?16000:8000, max_tokens = model == "deepseek-reasoner" ? 16000 : 8000,
stream = true, stream = true,
temperature = 0.2f, temperature = 0.2f,
messages = messageArr messages = messageArr
}; };
if (max_tokens != -1)
chatRep.max_tokens = max_tokens;
var tryCount = 10; var tryCount = 10;
while (--tryCount > 0) while (--tryCount > 0)
{ {
try try
{ {
var time = title+DateTime.Now.ToString("MMddHHmmss"); var time = title + DateTime.Now.ToString("MMddHHmmss");
var redisCached = new object[2] { chatRep, null }; var redisCached = new object[2] { chatRep, null };
RedisExpand.SetTaskGPTCached(task, time,chatRep); RedisExpand.SetTaskGPTCached(task, time, chatRep);
var chatResp = await chatClient.Chat(chatRep); var chatResp = await chatClient.Chat(chatRep);
var chatResContent = chatResp?.res; var chatResContent = chatResp?.res;
if (string.IsNullOrEmpty(chatResContent)) if (string.IsNullOrEmpty(chatResContent))
throw new Exception("GPT返回message无效结果"); throw new Exception("GPT返回message无效结果");
if (chatResp != null) { if (chatResp != null)
{
redisCached[1] = new object[] { chatResp.Value.res, chatResp.Value.u, chatResp.Value.reasoning }; redisCached[1] = new object[] { chatResp.Value.res, chatResp.Value.u, chatResp.Value.reasoning };
RedisExpand.SetTaskGPTCached(task, time, redisCached); RedisExpand.SetTaskGPTCached(task, time, redisCached);
} }
@ -359,6 +370,8 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
chatResContent = chatResContent?.Replace("}|{", "},{"); chatResContent = chatResContent?.Replace("}|{", "},{");
chatResContent = chatResContent?.Trim(); chatResContent = chatResContent?.Trim();
if (string.IsNullOrEmpty(chatResContent))
throw new Exception("ChatGPT返回结果无有效JSON");
var startsStr = typeof(T).IsArray ? "[" : "{"; var startsStr = typeof(T).IsArray ? "[" : "{";
var endStr = typeof(T).IsArray ? "]" : "}"; var endStr = typeof(T).IsArray ? "]" : "}";
if (!chatResContent.StartsWith(startsStr)) if (!chatResContent.StartsWith(startsStr))
@ -404,17 +417,17 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
var videoKnowDic = knowledgeInfos var videoKnowDic = knowledgeInfos
.GroupBy(s => s.Id) .GroupBy(s => s.Id)
.ToDictionary(s => s.Key, s => s.First()); .ToDictionary(s => s.Key, s => s.First());
var insertData =new List<VideoQuestionOSSDto>(); var insertData = new List<VideoQuestionOSSDto>();
var insertQuestionKonw = new List<VideoQuestionKonw>(); var insertQuestionKonw = new List<VideoQuestionKonw>();
foreach (var item in farmeArr) foreach (var item in farmeArr)
{ {
var knowInfoArr = videoKnowArr var knowInfoArr = videoKnowArr
.Where(s => item+20 >= s.StartTime && item <= s.EndTime) .Where(s => item + 20 >= s.StartTime && item <= s.EndTime)
.ToArray(); .ToArray();
if (knowInfoArr is null || knowInfoArr.Count() ==0) if (knowInfoArr is null || knowInfoArr.Count() == 0)
continue; continue;
var tryCount = 50; var tryCount = 50;
while (tryCount>1) while (tryCount > 1)
{ {
tryCount--; tryCount--;
try try
@ -424,10 +437,10 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
.ProcessImageAsync(new SimpleTexOcrRequest(filePath)); .ProcessImageAsync(new SimpleTexOcrRequest(filePath));
if (!sRes.Success) if (!sRes.Success)
continue; continue;
if(sRes.Result.res.value.Trim().Length<10)//总试题内容长度小于10 视为无效题目 if (sRes.Result.res.value.Trim().Length < 10)//总试题内容长度小于10 视为无效题目
break; break;
Console.WriteLine(DateTime.Now + $"=>{taskInfo.Id} 提取{knowInfoArr.First().StartTime}秒试题的试题内容"); 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 knowArr=JsonSerializer.Serialize(knowInfoArr.Select(s => new { s.KnowPointId, s.KnowPoint }));
var resFormat = """[{"Type":string(试题类型),"TopicStem":string(试题题干),"QuestionArr":[{"Question":string(子问题),"KnowPointId":(string)知识点ID}]}]"""; var resFormat = """[{"Type":string(试题类型),"TopicStem":string(试题题干),"QuestionArr":[{"Question":string(子问题),"KnowPointId":(string)知识点ID}]}]""";
var postMessages = var postMessages =
@ -444,7 +457,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
$"`{sRes.Result.res.value}`"; $"`{sRes.Result.res.value}`";
var resData = await ChatAsync<VideoQuestionOSSDto[]>(taskInfo.Id.ToString(), postMessages, "提取试题", "deepseek-chat"); var resData = await ChatAsync<VideoQuestionOSSDto[]>(taskInfo.Id.ToString(), postMessages, "提取试题", "deepseek-chat");
//var resData = await ChatAsync<VideoQuestionOSSDto[]>(taskInfo.Id.ToString(), postMessages, "提取试题"); //var resData = await ChatAsync<VideoQuestionOSSDto[]>(taskInfo.Id.ToString(), postMessages, "提取试题");
if(resData is null || resData.Count()==0) if (resData is null || resData.Count() == 0)
break; break;
foreach (var q in resData) foreach (var q in resData)
{ {
@ -460,13 +473,13 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
vq.Question = qt.Question; vq.Question = qt.Question;
vq.TopicId = TopicId; vq.TopicId = TopicId;
vq.Type = q.Type; vq.Type = q.Type;
if(string.IsNullOrEmpty(qt.KnowPointId)) if (string.IsNullOrEmpty(qt.KnowPointId))
continue;//重试 continue;//重试
insertData.Add(vq); insertData.Add(vq);
foreach (var kid in qt.KnowPointId.Split(",")) foreach (var kid in qt.KnowPointId.Split(","))
{ {
var tryOk = int.TryParse(kid.Split("|").First(),out int kidd); var tryOk = int.TryParse(kid.Split("|").First(), out int kidd);
if(!tryOk || !videoKnowDic.ContainsKey(kidd)) if (!tryOk || !videoKnowDic.ContainsKey(kidd))
continue;//跳过未识别知识点 continue;//跳过未识别知识点
insertQuestionKonw.Add(new VideoQuestionKonw() insertQuestionKonw.Add(new VideoQuestionKonw()
{ {
@ -491,7 +504,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
ossClient.AddVideoQuestionUrl(insertData); ossClient.AddVideoQuestionUrl(insertData);
await videoQuestionDB.AsDeleteable() await videoQuestionDB.AsDeleteable()
.Where(s=>s.VideoTaskId== taskInfo.Id) .Where(s => s.VideoTaskId == taskInfo.Id)
.ExecuteCommandAsync(); .ExecuteCommandAsync();
await videoQuestionKonwDB.AsDeleteable() await videoQuestionKonwDB.AsDeleteable()
.Where(s => s.VideoTaskId == taskInfo.Id) .Where(s => s.VideoTaskId == taskInfo.Id)
@ -525,7 +538,17 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
Course_Id = 27; Course_Id = 27;
break; break;
} }
switch (taskInfo?.VideoType)
{
case AttachmentsInfoType.:
case AttachmentsInfoType.:
case AttachmentsInfoType.:
break;
case AttachmentsInfoType.:
case AttachmentsInfoType.:
default:
throw new Exception("无效的课程类型");
}
var captionsArr = JsonSerializer.Deserialize<SenseVoiceRes[]>(taskInfo.Captions); var captionsArr = JsonSerializer.Deserialize<SenseVoiceRes[]>(taskInfo.Captions);
//处理视频授课章节 //处理视频授课章节
@ -543,16 +566,16 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
//合并字幕 //合并字幕
var captions = ExpandFunction.GetSpeakerCaptions(captionsArr); var captions = ExpandFunction.GetSpeakerCaptions(captionsArr);
var maxVideoTime = captions?.TimeBase?.LastOrDefault()?.End ?? 0; var maxVideoTime = captions?.TimeBase?.LastOrDefault()?.End ?? 0;
var questionRes = new List<VideoKnowRes>(); VideoKnowRes[]? questionRes =null;
while (true) var tryCount = 20;
while (tryCount-- > 0)
{ {
questionRes = new List<VideoKnowRes>();
//视频字幕分析 //视频字幕分析
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); var checkRes = await VerifySpanQuality(questionRes, taskInfo, captions, sections, Course_Id);
@ -575,7 +598,10 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
continue; continue;
} }
} }
if (tryCount == 0)
{
throw new Exception("重试次数过多!");
}
await RedisExpand.Redis await RedisExpand.Redis
.HMSetAsync(RedisExpandKey.Task(task), "VideoKnows", questionRes); .HMSetAsync(RedisExpandKey.Task(task), "VideoKnows", questionRes);

View File

@ -172,7 +172,7 @@ namespace VideoAnalysisCore.AICore.SherpaOnnx
if (!string.IsNullOrEmpty(task)) if (!string.IsNullOrEmpty(task))
{ {
Console.WriteLine(DateTime.Now + "=> SenseVoice 字幕数量" + res.Count); Console.WriteLine(DateTime.Now + "=> SenseVoice 字幕数量" + res.Count);
var captionsStr = JsonSerializer.Serialize(res); var captionsStr = res.ToJson();
await DbScoped.Sugar await DbScoped.Sugar
.Updateable<VideoTask>() .Updateable<VideoTask>()
.SetColumns(it => it.Captions == captionsStr) .SetColumns(it => it.Captions == captionsStr)

View File

@ -78,7 +78,7 @@ namespace VideoAnalysisCore.AICore.SherpaOnnx
}, nint.Zero); }, nint.Zero);
var res = segments.Select(s => new OfflineSpeakerRes(s)); var res = segments.Select(s => new OfflineSpeakerRes(s));
await RedisExpand.Redis.HSetAsync(RedisExpandKey.Task(task), "Speaker", res); await RedisExpand.Redis.HSetAsync(RedisExpandKey.Task(task), "Speaker", res);
var speakerStr = JsonSerializer.Serialize(res); var speakerStr = res.ToJson();
await DbScoped.Sugar await DbScoped.Sugar
.Updateable<VideoTask>() .Updateable<VideoTask>()
.SetColumns(it => it.Speaker == speakerStr) .SetColumns(it => it.Speaker == speakerStr)

View File

@ -52,7 +52,6 @@ namespace VideoAnalysisCore.Common
throw; throw;
} }
} }
/// <summary> /// <summary>
/// 程序配置 /// 程序配置
/// </summary> /// </summary>
@ -85,6 +84,7 @@ namespace VideoAnalysisCore.Common
/// </summary> /// </summary>
public static class ExpandFunction public static class ExpandFunction
{ {
static Dictionary<string, string> FormulaData; static Dictionary<string, string> FormulaData;
static string FormulaDataKey; static string FormulaDataKey;
/// <summary> /// <summary>
@ -92,6 +92,22 @@ namespace VideoAnalysisCore.Common
/// </summary> /// </summary>
public static string FrameName = "frame_"; public static string FrameName = "frame_";
/// <summary>
/// 对象转化为JSON字符串
/// </summary>
/// <param name="o">拓展对象</param>
/// <param name="WriteIndented">美化输出?</param>
/// <returns></returns>
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);
}
/// <summary> /// <summary>
/// 获取视频帧文件资源路径 /// 获取视频帧文件资源路径
/// </summary> /// </summary>
@ -100,7 +116,7 @@ namespace VideoAnalysisCore.Common
/// <returns></returns> /// <returns></returns>
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");
} }
/// <summary> /// <summary>
@ -113,7 +129,7 @@ namespace VideoAnalysisCore.Common
if (FormulaData is null) if (FormulaData is null)
{ {
var hotwords = JsonSerializer.Deserialize<HotwordMode[]>(File.ReadAllText(Path.Combine(AppCommon.AIModelFile, "Hotwords.json"))); var hotwords = JsonSerializer.Deserialize<HotwordMode[]>(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) foreach (var key in item.v)
FormulaData.Add(key, item.key); FormulaData.Add(key, item.key);
} }
@ -152,7 +168,7 @@ namespace VideoAnalysisCore.Common
/// <summary> /// <summary>
/// 获取Task处理后的 说话人字幕 /// 获取Task处理后的 说话人字幕
/// </summary> /// </summary>
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) if (captionsArr is null || captionsArr.Length == 0)
//|| speakerArr is null || speakerArr.Length == 0) //|| speakerArr is null || speakerArr.Length == 0)
@ -160,15 +176,15 @@ namespace VideoAnalysisCore.Common
// 教师说话人Id // 教师说话人Id
var techerId = speakerArr is null || !speakerArr.Any() var techerId = speakerArr is null || !speakerArr.Any()
? 0 ? 0
:speakerArr.GroupBy(s=>s.SpeakerIndex).Select(s => (s.Key,s.Sum(x=>x.Total))) : speakerArr.GroupBy(s => s.SpeakerIndex).Select(s => (s.Key, s.Sum(x => x.Total)))
.OrderByDescending(s=>s.Item2).First().Key; .OrderByDescending(s => s.Item2).First().Key;
var teacherSpeaking = 0f; var teacherSpeaking = 0f;
var studentSpeaking = 0f; var studentSpeaking = 0f;
var results = new Dictionary<SenseVoiceRes, List<int>>(); var results = new Dictionary<SenseVoiceRes, List<int>>();
var ss = new List<int> { 1 }; var ss = new List<int> { 1 };
if (speakerArr is null || speakerArr.Count() == 0) if (speakerArr is null || speakerArr.Count() == 0)
{ {
results = captionsArr.ToDictionary(s => s, s=> ss); results = captionsArr.ToDictionary(s => s, s => ss);
} }
else else
{ {
@ -213,7 +229,7 @@ namespace VideoAnalysisCore.Common
StudentSpeaking = (decimal)studentSpeaking, StudentSpeaking = (decimal)studentSpeaking,
TeacherSpeaking = (decimal)teacherSpeaking, TeacherSpeaking = (decimal)teacherSpeaking,
Captions = stringBuilder.ToString(), Captions = stringBuilder.ToString(),
TimeBase = results.Select(s=>new TimeBase() TimeBase = results.Select(s => new TimeBase()
{ {
Start = s.Key.Start, Start = s.Key.Start,
End = s.Key.End, End = s.Key.End,
@ -251,7 +267,7 @@ namespace VideoAnalysisCore.Common
{ {
try try
{ {
if(value is null || string.IsNullOrEmpty(value.ToString())) if (value is null || string.IsNullOrEmpty(value.ToString()))
return null; return null;
if (Enum.TryParse<T>(value.ToString(), true, out var result) && Enum.IsDefined(typeof(T), result)) if (Enum.TryParse<T>(value.ToString(), true, out var result) && Enum.IsDefined(typeof(T), result))
return result; return result;

View File

@ -26,7 +26,7 @@ namespace VideoAnalysisCore.Common
StackTrace = context.Exception.StackTrace, StackTrace = context.Exception.StackTrace,
}; };
// 将错误对象序列化为JSON格式 // 将错误对象序列化为JSON格式
var json = JsonSerializer.Serialize(errorObject); var json =errorObject.ToJson();
// 设置响应内容类型为JSON // 设置响应内容类型为JSON
context.HttpContext.Response.ContentType = "application/json"; context.HttpContext.Response.ContentType = "application/json";

View File

@ -128,7 +128,7 @@ namespace VideoAnalysisCore.Common.Expand
if (request.isolated_formula_wrapper != null) 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)); content.Add(new StringContent(isolatedWrapper), nameof(request.isolated_formula_wrapper));
parameters[nameof(request.isolated_formula_wrapper)] = isolatedWrapper; parameters[nameof(request.isolated_formula_wrapper)] = isolatedWrapper;
} }

View File

@ -54,7 +54,7 @@ namespace VideoAnalysisCore.Controllers
[HttpPost(Name = "NodePackage")] [HttpPost(Name = "NodePackage")]
public async Task<IActionResult> NodePackage(NodePackageReq[] reqArr) public async Task<IActionResult> 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) if (reqArr is null || reqArr.Count() == 0)
return BadRequest("无效视频列表数据"); return BadRequest("无效视频列表数据");
var videos = new List<VideoTask>(reqArr.Count()); var videos = new List<VideoTask>(reqArr.Count());

View File

@ -81,7 +81,7 @@ namespace VideoAnalysisCore.Job
var request = new HttpRequestMessage(HttpMethod.Post, postUrl); var request = new HttpRequestMessage(HttpMethod.Post, postUrl);
request.Headers.Add("Area", item.Area); // 直接添加到本次请求头 request.Headers.Add("Area", item.Area); // 直接添加到本次请求头
request.Headers.Add("HostIP", item.HostIP); // 直接添加到本次请求头 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); responseMessage = await apiClent.SendAsync(request);
if (responseMessage.IsSuccessStatusCode) if (responseMessage.IsSuccessStatusCode)