优化 88分分析视频结果即合格

修复 部分模型失效导致的死循环
修复 课程未能匹配知识点的极端情况重试
This commit is contained in:
小肥羊 2026-04-14 17:57:22 +08:00
parent 270395e939
commit 00e0664940
10 changed files with 68 additions and 51 deletions

View File

@ -42,8 +42,7 @@
"ApiKey": "sk-8BvvhESZIkgUbiaaJhglPxFa4o2X9H3xEv9lXELrWWwGxHWY" "ApiKey": "sk-8BvvhESZIkgUbiaaJhglPxFa4o2X9H3xEv9lXELrWWwGxHWY"
}, },
"ChatGpt": { "ChatGpt": {
"Host": "https://api.g4f.icu/", "Host": "https://api.oaibest.com/",
//"Host": "https://api.oaibest.com/",
"ApiKey": "sk-D15tBln31N7dI9Fi7lds7OySFv5tOEK7DMNsG5rY2E6DCr4s" "ApiKey": "sk-D15tBln31N7dI9Fi7lds7OySFv5tOEK7DMNsG5rY2E6DCr4s"
}, },
"DeepSeek": { "DeepSeek": {

View File

@ -24,6 +24,7 @@ namespace VideoAnalysisCore.AICore.GPT
//public const string Gemini_3_Chat_thinking = "gemini-3-pro-preview-thinking"; //public const string Gemini_3_Chat_thinking = "gemini-3-pro-preview-thinking";
public const string Gemini_3_Chat = "gemini-3.1-pro-preview"; public const string Gemini_3_Chat = "gemini-3.1-pro-preview";
//public const string Gemini_3_Chat_flash = "gemini-3-flash-preview"; //public const string Gemini_3_Chat_flash = "gemini-3-flash-preview";
public const string Gemini_31_Chat_flash = "gemini-3.1-flash-lite-preview"; //已失效
//public const string Gemini_31_Chat_flash = "gemini-3.1-flash-lite-preview";
} }
} }

View File

@ -27,6 +27,7 @@ using Dm.util;
using static System.Net.Mime.MediaTypeNames; using static System.Net.Mime.MediaTypeNames;
using VideoAnalysisCore.AICore.GPT.DeepSeek; using VideoAnalysisCore.AICore.GPT.DeepSeek;
using VideoAnalysisCore.AICore.GPT.Gemini; using VideoAnalysisCore.AICore.GPT.Gemini;
using static System.Collections.Specialized.BitVector32;
namespace VideoAnalysisCore.AICore.GPT namespace VideoAnalysisCore.AICore.GPT
{ {
@ -115,10 +116,10 @@ namespace VideoAnalysisCore.AICore.GPT
await _workflowManager.AddTaskLog(taskInfo.Id, "==>2.开始分析视频内容知识点"); await _workflowManager.AddTaskLog(taskInfo.Id, "==>2.开始分析视频内容知识点");
List<VideoKnowRes> konwRes; List<VideoKnowRes> konwRes;
var knowOK = false; var knowOK = false;
var chatClentArr = new GPTClient[] { chatGPTClient, geminiClient, bset_deepSeekClient }; //var chatClentArr = new GPTClient[] { chatGPTClient, geminiClient, bset_deepSeekClient };
for (int i = 0; i < 3; i++) for (int i = 0; i < 3; i++)
{ {
konwRes = await chatClentArr[i].ChatAsync<List<VideoKnowRes>>(taskInfo.Id.ToString(), knowMessages, "知识点"); konwRes = await chatGPTClient.ChatAsync<List<VideoKnowRes>>(taskInfo.Id.ToString(), knowMessages, "知识点");
// 分析结果的片段数量与预期不匹配 // 分析结果的片段数量与预期不匹配
if (questionRes.Count() != konwRes.Count()) continue; if (questionRes.Count() != konwRes.Count()) continue;
for (int xi = 0; xi < konwRes.Count(); xi++) for (int xi = 0; xi < konwRes.Count(); xi++)
@ -193,7 +194,7 @@ namespace VideoAnalysisCore.AICore.GPT
$"字幕列表 {rCaptionArr}。" + $"字幕列表 {rCaptionArr}。" +
$"输出格式 json字符串 对象格式{fileNameResFormat}"; $"输出格式 json字符串 对象格式{fileNameResFormat}";
var task = taskInfo.Id.ToString(); var task = taskInfo.Id.ToString();
var fileNameInfoRes = await geminiClient.ChatAsync<FileNameInfo>(task, fileNamePostMessages, "授课章节"); var fileNameInfoRes = await chatGPTClient.ChatAsync<FileNameInfo>(task, fileNamePostMessages, "授课章节");
taskInfo.Sections = fileNameInfoRes.; taskInfo.Sections = fileNameInfoRes.;
await videoTaskDB.AsUpdateable() await videoTaskDB.AsUpdateable()
.SetColumns(it => it.Sections == fileNameInfoRes.) .SetColumns(it => it.Sections == fileNameInfoRes.)
@ -282,11 +283,43 @@ namespace VideoAnalysisCore.AICore.GPT
JSON{resFormat} JSON{resFormat}
"""; """;
var improved = await geminiClient.ChatAsync<List<VideoKnowRes>>(taskInfo.Id.ToString(), message, "分段优化"); //var improved = await geminiClient.ChatAsync<List<VideoKnowRes>>(taskInfo.Id.ToString(), message, "分段优化");
if (improved is null || improved.Count() != questionRes.Count()) //if (improved is null || improved.Count() != questionRes.Count())
return null; return null;
return improved.OrderBy(s => s.StartTime ?? 0).ToList(); //return improved.OrderBy(s => s.StartTime ?? 0).ToList();
}
private async Task<(string, List<KnowledgeInfo>)> GetKnowledgeInfos(VideoTask taskInfo,long Course_Id)
{
List<KnowledgeInfo>? knowledgeInfos =null;
string? sections = null;
for (int i = 0; i < 3; i++)
{
sections = await GetSections(taskInfo, Course_Id);
var know = await knowledgeInfoDB.GetFirstAsync(s => s.Course_Id == Course_Id && s.Name == sections);
if (know is null)
{
await _workflowManager.AddTaskLog(taskInfo.Id, $"==>识别的知识点无效 {sections}");
continue;
}
var kInfo = await knowledgeInfoDB.GetByIdAsync(know.Parent_Id);
if (know.Parent_Id == 0)
kInfo = know;
try
{
knowledgeInfos = await knowledgeInfoDB.AsQueryable()
.ToChildListAsync(s => s.Parent_Id, kInfo.Parent_Id == 0 ? kInfo.Id : kInfo.Parent_Id);
}
catch (Exception)
{
await _workflowManager.AddTaskLog(taskInfo.Id, $"==>识别的知识没有对应的子知识点 {sections } {kInfo?.Name}");
continue;
}
}
if(knowledgeInfos is null)
throw new Exception("多次识别后未能识别到有效课堂知识点=>" + sections);
return new(sections, knowledgeInfos);
} }
/// <summary> /// <summary>
@ -308,12 +341,13 @@ namespace VideoAnalysisCore.AICore.GPT
[ [
async (m)=>await bset_deepSeekClient async (m)=>await bset_deepSeekClient
.ChatAsync<List<SenseVoiceInput>>(taskInfo.Id.ToString(), m, "优化字幕",ChatGPTType.Deepseek_v32,8_000), .ChatAsync<List<SenseVoiceInput>>(taskInfo.Id.ToString(), m, "优化字幕",ChatGPTType.Deepseek_v32,8_000),
async (m)=>await bset_deepSeekClient //async (m)=>await bset_deepSeekClient
.ChatAsync<List<SenseVoiceInput>>(taskInfo.Id.ToString(), m, "优化字幕",ChatGPTType.Deepseek_Chat,8_000), // .ChatAsync<List<SenseVoiceInput>>(taskInfo.Id.ToString(), m, "优化字幕",ChatGPTType.Deepseek_Chat,8_000),
async (m)=>await chatGPTClient //async (m)=>await chatGPTClient
.ChatAsync<List<SenseVoiceInput>>(taskInfo.Id.ToString(), m, "优化字幕",ChatGPTType.GPT54_mini,16_000), // .ChatAsync<List<SenseVoiceInput>>(taskInfo.Id.ToString(), m, "优化字幕",ChatGPTType.GPT54_mini,16_000),
async (m)=>await geminiClient //async (m)=>await geminiClient
.ChatAsync<List<SenseVoiceInput>>(taskInfo.Id.ToString(), m, "优化字幕",ChatGPTType.Gemini_3_Chat,16_000), ]; // .ChatAsync<List<SenseVoiceInput>>(taskInfo.Id.ToString(), m, "优化字幕",ChatGPTType.Gemini_3_Chat,16_000),
];
await Parallel.ForAsync(0, totalCount, await Parallel.ForAsync(0, totalCount,
new ParallelOptions() new ParallelOptions()
#if DEBUG #if DEBUG
@ -731,24 +765,10 @@ namespace VideoAnalysisCore.AICore.GPT
var captionsArr = JsonSerializer.Deserialize<SenseVoiceRes[]>(taskInfo.Captions); var captionsArr = JsonSerializer.Deserialize<SenseVoiceRes[]>(taskInfo.Captions);
//处理视频授课章节 //处理视频授课章节
var sections = await GetSections(taskInfo, Course_Id); var kr = await GetKnowledgeInfos(taskInfo, Course_Id);
var sections = kr.Item1;
var know = await knowledgeInfoDB.GetFirstAsync(s => s.Course_Id == Course_Id && s.Name == sections); List<KnowledgeInfo>? knowledgeInfos = kr.Item2;
if (know is null)
throw new Exception("未能找到对应知识点=>" + sections);
List<KnowledgeInfo>? knowledgeInfos = new List<KnowledgeInfo>();
var kInfo = await knowledgeInfoDB.GetByIdAsync(know.Parent_Id);
if (know.Parent_Id == 0)
kInfo = know;
try
{
knowledgeInfos = await knowledgeInfoDB.AsQueryable()
.ToChildListAsync(s => s.Parent_Id, kInfo.Parent_Id == 0 ? kInfo.Id : kInfo.Parent_Id);
}
catch (Exception)
{
throw new Exception("没有对应的子知识点=>" + sections + " " + kInfo?.Name);
}
//AI优化字幕 //AI优化字幕
captionsArr = await OptimizeSubtitles(taskInfo, captionsArr, sections); captionsArr = await OptimizeSubtitles(taskInfo, captionsArr, sections);
@ -801,7 +821,7 @@ namespace VideoAnalysisCore.AICore.GPT
// } // }
//} //}
if (checkRes != null && checkRes.Score >= 90) if (checkRes != null && checkRes.Score >= 88)
{ {
//写入知识点 //写入知识点
await videoKonwPointDB.DeleteAsync(s => s.VideoTaskId == taskInfo.Id); await videoKonwPointDB.DeleteAsync(s => s.VideoTaskId == taskInfo.Id);
@ -838,7 +858,7 @@ namespace VideoAnalysisCore.AICore.GPT
continue; continue;
} }
} }
if (tryCount == 0) if (tryCount < 1)
{ {
throw new Exception("重试次数过多!"); throw new Exception("重试次数过多!");
} }

View File

@ -46,7 +46,7 @@ namespace VideoAnalysisCore.AICore.GPT.Gemini
Message[] messageArr = [ Message[] messageArr = [
new Message(postMessages,"user"), new Message(postMessages,"user"),
]; ];
model = model ?? ChatGPTType.Gemini_31_Chat_flash; model = model ?? ChatGPTType.Gemini_3_Chat;
messageArr = messageArr.Where(s => s != null).ToArray(); messageArr = messageArr.Where(s => s != null).ToArray();
var chatReq = new ChatRequest var chatReq = new ChatRequest
{ {

View File

@ -81,6 +81,7 @@ namespace VideoAnalysisCore.Common
/// </summary> /// </summary>
public static string Task(object taskId) => BaseKey + "Info:" + taskId; public static string Task(object taskId) => BaseKey + "Info:" + taskId;
public static string IDTask => BaseKey + "Services:" + AppCommon.Config.ID; public static string IDTask => BaseKey + "Services:" + AppCommon.Config.ID;
public static string DeviceTaskLog(string deviceId) => BaseKey + "Services:" + deviceId;
/// <summary> /// <summary>
/// 在线设备Key集合 (已弃用,直接扫描 Heartbeat) /// 在线设备Key集合 (已弃用,直接扫描 Heartbeat)
/// </summary> /// </summary>

View File

@ -94,7 +94,7 @@ namespace VideoAnalysisCore.Common
public override async Task TaskEnd(string task) public override async Task TaskEnd(string task)
{ {
var tId = long.Parse(task); var tId = long.Parse(task);
await base.TaskEnd(task); //await base.TaskEnd(task);
// TidySlide 工作流结束时清理文件 // TidySlide 工作流结束时清理文件
try try

View File

@ -350,7 +350,7 @@ namespace VideoAnalysisCore.Controllers.Dto
public GradeEnum? GradeId { get; set; } public GradeEnum? GradeId { get; set; }
public GradeSemesterEnum? GradeSemester { get; set; } public GradeSemesterEnum? GradeSemester { get; set; }
public long? TextBookVersionId { get; set; } public long? TextBookVersionId { get; set; }
public string[]? KnowPointIdArr { get; set; } public string[]? KnowPointStrArr { get; set; }
public string? Theme { get; set; } public string? Theme { get; set; }
public string? Content { get; set; } public string? Content { get; set; }
public int PageIndex { get; set; } = 0; public int PageIndex { get; set; } = 0;

View File

@ -306,14 +306,14 @@ namespace VideoAnalysisCore.Controllers
var pageIndex = req.PageIndex < 0 ? 0 : req.PageIndex; var pageIndex = req.PageIndex < 0 ? 0 : req.PageIndex;
var pageSize = req.PageSize <= 0 ? 200 : req.PageSize > 500 ? 500 : req.PageSize; var pageSize = req.PageSize <= 0 ? 200 : req.PageSize > 500 ? 500 : req.PageSize;
string[]? knowArr = null;
if (req.KnowPointIdArr is not null && req.KnowPointIdArr.Length > 0) if (req.KnowPointStrArr is not null && req.KnowPointStrArr.Length > 0)
{ {
var knowArr = req.KnowPointIdArr.Where(s => !string.IsNullOrWhiteSpace(s)).Distinct().ToArray(); knowArr = req.KnowPointStrArr.Where(s => !string.IsNullOrWhiteSpace(s)).Select(s=>s.Trim()).Distinct().ToArray();
if (knowArr.Length > 0) if (knowArr.Length > 0)
{ {
stageQuery = stageQuery.Where(s => SqlFunc.Subqueryable<VideoKonwPoint>() stageQuery = stageQuery.Where(s => SqlFunc.Subqueryable<VideoKonwPoint>()
.Where(k => k.StageId == s.Id && k.KnowPointId != null && knowArr.Contains(k.KnowPointId)) .Where(k => k.StageId == s.Id && k.KnowPoint != null && knowArr.Contains(k.KnowPoint))
.Any()); .Any());
} }
} }
@ -326,12 +326,8 @@ namespace VideoAnalysisCore.Controllers
var taskIdArr = stagePageArr.Select(s => s.VideoTaskId).ToArray(); var taskIdArr = stagePageArr.Select(s => s.VideoTaskId).ToArray();
var kpQuery = videoKonwPointDB.AsQueryable() var kpQuery = videoKonwPointDB.AsQueryable()
.Where(s => taskIdArr.Contains(s.VideoTaskId) && s.KnowPointId != null); .Where(s => taskIdArr.Contains(s.VideoTaskId) && s.KnowPointId != null);
if (req.KnowPointIdArr is not null && req.KnowPointIdArr.Length > 0) if (knowArr.Length > 0)
{ kpQuery = kpQuery.Where(s => knowArr.Contains(s.KnowPointId));
var knowArr = req.KnowPointIdArr.Where(s => !string.IsNullOrWhiteSpace(s)).Distinct().ToArray();
if (knowArr.Length > 0)
kpQuery = kpQuery.Where(s => knowArr.Contains(s.KnowPointId));
}
var kpArr = await kpQuery var kpArr = await kpQuery
.Select(s => new { s.StageId, s.KnowPoint }) .Select(s => new { s.StageId, s.KnowPoint })

View File

@ -527,7 +527,7 @@ namespace VideoAnalysisCore.Controllers
foreach (var deviceId in onlineDevices) foreach (var deviceId in onlineDevices)
{ {
var key = RedisExpandKey.BaseKey + "Services:" + deviceId; var key = RedisExpandKey.DeviceTaskLog(deviceId) ;
var tasks = redisManager.Redis.LRange<long>(key, 0, 999); var tasks = redisManager.Redis.LRange<long>(key, 0, 999);
oldTaskArr.AddRange(tasks); oldTaskArr.AddRange(tasks);
} }
@ -535,7 +535,7 @@ namespace VideoAnalysisCore.Controllers
else else
{ {
// 获取指定节点 // 获取指定节点
var key = RedisExpandKey.BaseKey + "Services:" + model.DeviceId; var key = RedisExpandKey.DeviceTaskLog(model.DeviceId);
oldTaskArr = redisManager.Redis.LRange<long>(key, 0, 999).ToList(); oldTaskArr = redisManager.Redis.LRange<long>(key, 0, 999).ToList();
} }

View File

@ -11,7 +11,7 @@ namespace VideoAnalysisCore.Model.蓝鲸智库
/// <summary> /// <summary>
/// 蓝鲸智库 知识点表 /// 蓝鲸智库 知识点表
/// </summary> /// </summary>
[SugarTable("knowledgeinfo")] [SugarTable("knowledgeinfo_hy")]
[Tenant("1001")] [Tenant("1001")]
public class KnowledgeInfo public class KnowledgeInfo
{ {