优化 调试工作流1的AI分析流程(知识点权重,来源,AI复查复检...)
This commit is contained in:
parent
b4b02cfbd3
commit
a2d14487cb
|
|
@ -42,7 +42,7 @@ namespace VideoAnalysisCore.AICore.GPT.ChatGPT
|
||||||
/// <param name="max_tokens">最大token <para>不设置默认最大值 16000/8000</para></param>
|
/// <param name="max_tokens">最大token <para>不设置默认最大值 16000/8000</para></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
/// <exception cref="Exception"></exception>
|
/// <exception cref="Exception"></exception>
|
||||||
public override async Task<T> ChatAsync<T>(string task, string postMessages, string title, string model =null, int max_tokens = 16000)
|
public override async Task<T> ChatAsync<T>(string task, string postMessages, string title, string model =null, int max_tokens = 32000)
|
||||||
{
|
{
|
||||||
Message[] messageArr = [
|
Message[] messageArr = [
|
||||||
new Message(postMessages,"user"),
|
new Message(postMessages,"user"),
|
||||||
|
|
@ -53,7 +53,7 @@ namespace VideoAnalysisCore.AICore.GPT.ChatGPT
|
||||||
taskId = task,
|
taskId = task,
|
||||||
title = title,
|
title = title,
|
||||||
model = model ?? ChatGPTType.Deepseek_Reasoner,
|
model = model ?? ChatGPTType.Deepseek_Reasoner,
|
||||||
max_tokens = model == ChatGPTType.Deepseek_Reasoner ? 16000 : max_tokens,
|
max_tokens = model == ChatGPTType.Deepseek_Reasoner ? 32000 : max_tokens,
|
||||||
stream = true,
|
stream = true,
|
||||||
temperature = 0.2f,
|
temperature = 0.2f,
|
||||||
messages = messageArr
|
messages = messageArr
|
||||||
|
|
|
||||||
|
|
@ -34,9 +34,10 @@ namespace VideoAnalysisCore.AICore.GPT.Dto
|
||||||
}
|
}
|
||||||
public class VideoKnowPointDto
|
public class VideoKnowPointDto
|
||||||
{
|
{
|
||||||
|
public float KnowPointWeight { get; set; }
|
||||||
public string KnowPoint { get; set; }
|
public string KnowPoint { get; set; }
|
||||||
public string KnowPointId { get; set; }
|
public string KnowPointId { get; set; }
|
||||||
public float KnowSourceTime { get; set; }
|
public string KnowSource { get; set; }
|
||||||
}
|
}
|
||||||
public class VideoKnowRes
|
public class VideoKnowRes
|
||||||
{
|
{
|
||||||
|
|
@ -64,6 +65,10 @@ namespace VideoAnalysisCore.AICore.GPT.Dto
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual string? KnowPoint { get; set; }
|
public virtual string? KnowPoint { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
/// 知识点权重
|
||||||
|
/// </summary>
|
||||||
|
public virtual float? KnowPointWeight { get; set; }
|
||||||
|
/// <summary>
|
||||||
/// 知识点ID
|
/// 知识点ID
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual string? KnowPointId { get; set; }
|
public virtual string? KnowPointId { get; set; }
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@ using System.IO;
|
||||||
using VideoAnalysisCore.AICore.GPT.ChatGPT;
|
using VideoAnalysisCore.AICore.GPT.ChatGPT;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
using FFmpeg.NET.Services;
|
||||||
|
using NetTaste;
|
||||||
|
|
||||||
namespace VideoAnalysisCore.AICore.GPT
|
namespace VideoAnalysisCore.AICore.GPT
|
||||||
{
|
{
|
||||||
|
|
@ -156,7 +158,7 @@ namespace VideoAnalysisCore.AICore.GPT
|
||||||
/// <param name="max_tokens">最大token <para>不设置默认最大值 16000/8000</para></param>
|
/// <param name="max_tokens">最大token <para>不设置默认最大值 16000/8000</para></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
/// <exception cref="Exception"></exception>
|
/// <exception cref="Exception"></exception>
|
||||||
public async Task<T> ChatAsync<T>(ChatRequest chatRep)
|
public async Task<T> ChatAsync<T>(ChatRequest chatRep) where T:class,new()
|
||||||
{
|
{
|
||||||
var tryCount = 10;
|
var tryCount = 10;
|
||||||
while (tryCount-- > 0)
|
while (tryCount-- > 0)
|
||||||
|
|
@ -186,8 +188,14 @@ namespace VideoAnalysisCore.AICore.GPT
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(chatResContent))
|
if (string.IsNullOrEmpty(chatResContent))
|
||||||
throw new Exception($"GPT返回结果无有效JSON =>{chatResp?.res}");
|
throw new Exception($"GPT返回结果无有效JSON =>{chatResp?.res}");
|
||||||
var startsStr = typeof(T).IsArray ? "[" : "{";
|
var startsStr = "{";
|
||||||
var endStr = typeof(T).IsArray ? "]" : "}";
|
var endStr = "}";
|
||||||
|
var resT = new T();
|
||||||
|
if (resT is Array || resT is System.Collections.IList || resT is System.Collections.IList)
|
||||||
|
{
|
||||||
|
startsStr = "[";
|
||||||
|
endStr = "]";
|
||||||
|
}
|
||||||
if (!chatResContent.StartsWith(startsStr))
|
if (!chatResContent.StartsWith(startsStr))
|
||||||
chatResContent = startsStr + chatResContent;
|
chatResContent = startsStr + chatResContent;
|
||||||
if (!chatResContent.EndsWith(endStr))
|
if (!chatResContent.EndsWith(endStr))
|
||||||
|
|
@ -271,7 +279,7 @@ namespace VideoAnalysisCore.AICore.GPT
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
/// <exception cref="Exception"></exception>
|
/// <exception cref="Exception"></exception>
|
||||||
public virtual Task<T> ChatAsync<T>(string task, string postMessages, string title,
|
public virtual Task<T> ChatAsync<T>(string task, string postMessages, string title,
|
||||||
string model = null, int max_tokens = 16000)
|
string model = null, int max_tokens = 16000) where T : class, new()
|
||||||
{
|
{
|
||||||
throw new Exception("需要实现");
|
throw new Exception("需要实现");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ using System.Collections.Generic;
|
||||||
using UserCenter.Model.Enum;
|
using UserCenter.Model.Enum;
|
||||||
using Dm.filter;
|
using Dm.filter;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace VideoAnalysisCore.AICore.GPT.DeepSeek
|
namespace VideoAnalysisCore.AICore.GPT.DeepSeek
|
||||||
{
|
{
|
||||||
|
|
@ -81,28 +82,37 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
|
||||||
questionRes = questionRes.Where(s => s != null)
|
questionRes = questionRes.Where(s => s != null)
|
||||||
.OrderBy(s => s.StartTime).ToList();
|
.OrderBy(s => s.StartTime).ToList();
|
||||||
var thems = questionRes.Adapt<VideoKnowQueryDto[]>().ToJson();
|
var thems = questionRes.Adapt<VideoKnowQueryDto[]>().ToJson();
|
||||||
var checkResFormat1 = """[{"StartTime":开始秒(number),"TextbookSource":教材来源(string),"KnowPoints":[{"KnowSourceTime":"知识点来源的开始秒(number)","KnowPoint":知识点名称(string),"KnowPointId":知识点Id(string)}]}]""";
|
var checkResFormat1 = """[{"StartTime":12.3,"TextbookSource":"课本","KnowPoints":[{"KnowPointWeight":0.5,"KnowSource":"开始时间(秒),匹配的原因","KnowPoint":"知识点名称","KnowPointId":"123"}]}]""";
|
||||||
var knowMessages =
|
var knowMessages =
|
||||||
$"我针对{taskInfo.Subject}课堂授课视频分析出了视频的授课阶段片段。\n" +
|
$"""
|
||||||
$"现在需要你通过每个片段的内容总结来分配正确的知识点(单个片段允许多个知识点)。\n" +
|
角色:你是一位{taskInfo.Subject}学科教研老师。
|
||||||
$"KnowSourceTime字段 需要提供出知识点被匹配的字幕内容最开始的时间来源。\n" +
|
任务:为每个【视频分段】分配对应的知识点(可多个),并补充来源信息。
|
||||||
$"TextbookSource字段 需要你分析出单个片段内讲述内容所属的教材范围 例如 (范围限定在 课本/试卷/挹青苑/其他)。\n" +
|
字段说明:
|
||||||
$"这是我的分段 {thems}。\n" +
|
- TextbookSource:该分段讲授内容所属教材来源,仅允许取值:课本/试卷/挹青苑/其他
|
||||||
$"课堂内容与{sections}章节相关\n" +
|
- KnowPoints:数组。每个元素代表一个知识点匹配结果
|
||||||
$"最后请确保分配的知识点是用户提供的,并且一定正确合理!\n" +
|
- KnowPoint:知识点名称(必须来自我提供的列表)
|
||||||
$"返回的片段数量与传入片段数量一致!(硬性条件)\n" +
|
- KnowPointId:知识点ID(必须与 KnowPoint 对应)
|
||||||
$"输出内容只返回json格式({checkResFormat1})\n" +
|
- KnowPointWeight:知识点在本分段的占比权重(最高为1,单个分段内的知识点权重之和必须等于1)
|
||||||
$" 格式 (方法点Id|方法点名称) \n" +
|
- KnowSource:该知识点在字幕中被首次提及的“开始秒,为什么匹配的原因(最多50字)”
|
||||||
$"提供的`知识点名称({knows})。\n";
|
强制约束(硬性条件):
|
||||||
|
1) 输出数组长度必须与输入分段长度一致,且顺序一致;不得新增/删除/合并分段。
|
||||||
|
2) 每个对象的 StartTime 必须与输入分段的 StartTime 完全一致(不得改动)。
|
||||||
|
3) KnowPoints 允许为空数组(表示未能匹配任何知识点),但不要输出空字符串或用逗号拼接。
|
||||||
|
4) 只输出 JSON(禁止 Markdown/解释/额外文本)。
|
||||||
|
输入分段:{thems}
|
||||||
|
章节:{sections}
|
||||||
|
知识点列表(Id|Name):{knows}
|
||||||
|
输出格式示例:{checkResFormat1}
|
||||||
|
""";
|
||||||
await redisManager.AddTaskLog(taskInfo.Id, "==>2.开始分析视频内容知识点");
|
await redisManager.AddTaskLog(taskInfo.Id, "==>2.开始分析视频内容知识点");
|
||||||
VideoKnowRes[] konwRes;
|
List<VideoKnowRes> konwRes;
|
||||||
var knowOK = false;
|
var knowOK = false;
|
||||||
var chatClentArr = new GPTClient[] { chatGPTClient, geminiClient, deepSeekClient };
|
var chatClentArr = new GPTClient[] { chatGPTClient, geminiClient, deepSeekClient };
|
||||||
for (int i = 0; i < 3; i++)
|
for (int i = 0; i < 3; i++)
|
||||||
{
|
{
|
||||||
konwRes = await chatClentArr[i].ChatAsync<VideoKnowRes[]>(taskInfo.Id.ToString(), knowMessages, "知识点");
|
konwRes = await chatClentArr[i].ChatAsync<List<VideoKnowRes>>(taskInfo.Id.ToString(), knowMessages, "知识点");
|
||||||
// 分析结果的片段数量与预期不匹配
|
// 分析结果的片段数量与预期不匹配
|
||||||
if (questionRes.Count() != konwRes.Length) continue;
|
if (questionRes.Count() != konwRes.Count()) continue;
|
||||||
for (int xi = 0; xi < konwRes.Count(); xi++)
|
for (int xi = 0; xi < konwRes.Count(); xi++)
|
||||||
{
|
{
|
||||||
questionRes[xi].KnowPoints = konwRes[xi].KnowPoints;
|
questionRes[xi].KnowPoints = konwRes[xi].KnowPoints;
|
||||||
|
|
@ -132,7 +142,9 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
|
||||||
EndTime = s.EndTime,
|
EndTime = s.EndTime,
|
||||||
StageId = StageId,
|
StageId = StageId,
|
||||||
KnowPoint = x.KnowPoint,
|
KnowPoint = x.KnowPoint,
|
||||||
KnowSourceTime = x.KnowSourceTime,
|
KnowPointWeight=x.KnowPointWeight,
|
||||||
|
TextbookSource = s.TextbookSource,
|
||||||
|
KnowSource = x.KnowSource,
|
||||||
KnowPointId = knowDic[x.KnowPoint].ToString(),
|
KnowPointId = knowDic[x.KnowPoint].ToString(),
|
||||||
TagId = taskInfo.TagId,
|
TagId = taskInfo.TagId,
|
||||||
VideoTaskId = taskInfo.Id,
|
VideoTaskId = taskInfo.Id,
|
||||||
|
|
@ -197,7 +209,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
|
||||||
var pptFormat = taskInfo.VideoType == AttachmentsInfoType.复习
|
var pptFormat = taskInfo.VideoType == AttachmentsInfoType.复习
|
||||||
? "这堂课是习题课,所讲解内容几乎都是试题。"
|
? "这堂课是习题课,所讲解内容几乎都是试题。"
|
||||||
: string.Empty;
|
: string.Empty;
|
||||||
var checkResFormat = """{"Score":85.5,"MinusScore":"简洁的扣分原因","Suggestion":"改进建议"}""";
|
var checkResFormat = """{"Score":65.5,"MinusScore":"简洁的扣分原因","Suggestion":"简洁的改进建议"}""";
|
||||||
var checkMessage =
|
var checkMessage =
|
||||||
$"""
|
$"""
|
||||||
请你担任一位专业的视频内容分析教研老师,擅长评估视频内容的结构和逻辑流暢度。
|
请你担任一位专业的视频内容分析教研老师,擅长评估视频内容的结构和逻辑流暢度。
|
||||||
|
|
@ -209,8 +221,9 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
|
||||||
知识点分配:检查分段内的知识点是否与分段Conten有关联,知识点分配给这个分段是否合理(硬性指标)。
|
知识点分配:检查分段内的知识点是否与分段Conten有关联,知识点分配给这个分段是否合理(硬性指标)。
|
||||||
逻辑过渡:评估分段之间的过渡是否自然流畅,后一段是否是前一段内容的合理延伸或转折。
|
逻辑过渡:评估分段之间的过渡是否自然流畅,后一段是否是前一段内容的合理延伸或转折。
|
||||||
综合评分:
|
综合评分:
|
||||||
请基于以上分析,提供一个0-100的综合得分(70分及格)。
|
请基于以上分析,提供一个0-100的综合得分(70分及格,打分一定要严谨,总分一定要准确)。
|
||||||
详细说明打分理由,并逐条对应到上述评估维度。
|
MinusScore: 详细说明打分理由,并逐条对应到上述评估维度。
|
||||||
|
Suggestion: 基于扣分原因提出针对分段方案的改进意见(请忽略掉分段没有结束时间的问题我会自己处理)。
|
||||||
输入数据格式说明:
|
输入数据格式说明:
|
||||||
分段方案: {thems}
|
分段方案: {thems}
|
||||||
字幕文本: 格式为说话人:开始秒:结束秒:内容|下一段字幕。完整内容为:{captions.Captions}
|
字幕文本: 格式为说话人:开始秒:结束秒:内容|下一段字幕。完整内容为:{captions.Captions}
|
||||||
|
|
@ -257,8 +270,8 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
|
||||||
输出格式(仅 JSON):{resFormat}
|
输出格式(仅 JSON):{resFormat}
|
||||||
""";
|
""";
|
||||||
|
|
||||||
var improved = await geminiClient.ChatAsync<VideoKnowRes[]>(taskInfo.Id.ToString(), message, "分段优化");
|
var improved = await geminiClient.ChatAsync<List<VideoKnowRes>>(taskInfo.Id.ToString(), message, "分段优化");
|
||||||
if (improved is null || improved.Length != 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();
|
||||||
|
|
@ -271,7 +284,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
|
||||||
private async Task<SenseVoiceRes[]> OptimizeSubtitles(VideoTask taskInfo,
|
private async Task<SenseVoiceRes[]> OptimizeSubtitles(VideoTask taskInfo,
|
||||||
SenseVoiceRes[] captionsArr, string sections)
|
SenseVoiceRes[] captionsArr, string sections)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(taskInfo.CaptionsAI))
|
if (!string.IsNullOrEmpty(taskInfo.CaptionsAI) && taskInfo.CaptionsAI!="[]")
|
||||||
return JsonSerializer.Deserialize<SenseVoiceRes[]>(taskInfo.CaptionsAI);
|
return JsonSerializer.Deserialize<SenseVoiceRes[]>(taskInfo.CaptionsAI);
|
||||||
var subject = taskInfo.Subject.ToString();
|
var subject = taskInfo.Subject.ToString();
|
||||||
var newCaptionsList = new List<SenseVoiceRes>(captionsArr.Length);
|
var newCaptionsList = new List<SenseVoiceRes>(captionsArr.Length);
|
||||||
|
|
@ -306,10 +319,10 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
|
||||||
$"待优化字幕内容:\n" +
|
$"待优化字幕内容:\n" +
|
||||||
$"{nowCaptionStr}\n" +
|
$"{nowCaptionStr}\n" +
|
||||||
$"最终核对:请确保输出 JSON 中包含的字幕条数与输入的字幕条数完全对应。";
|
$"最终核对:请确保输出 JSON 中包含的字幕条数与输入的字幕条数完全对应。";
|
||||||
string[]? resData = null;
|
List<string>? resData = null;
|
||||||
for (int i = 0; i < 3; i++)
|
for (int i = 0; i < 3; i++)
|
||||||
{
|
{
|
||||||
resData = await chatClentArr[i].ChatAsync<string[]>(taskInfo.Id.ToString(), postMessages, "优化字幕", ChatGPTType.Deepseek_Chat, 8000);
|
resData = await chatClentArr[i].ChatAsync<List<string>>(taskInfo.Id.ToString(), postMessages, "优化字幕", ChatGPTType.Deepseek_Chat, 8000);
|
||||||
if (resData.Count() == cArr.Count())
|
if (resData.Count() == cArr.Count())
|
||||||
break;
|
break;
|
||||||
else
|
else
|
||||||
|
|
@ -318,7 +331,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
|
||||||
|
|
||||||
if (resData.Count() != cArr.Count())
|
if (resData.Count() != cArr.Count())
|
||||||
{
|
{
|
||||||
resData = cStrArr.ToArray();
|
resData = cStrArr.ToList();
|
||||||
await redisManager.AddTaskLog(taskInfo.Id, $"==>字幕优化 分段{s} AI结果数量不匹配 采用原始值");
|
await redisManager.AddTaskLog(taskInfo.Id, $"==>字幕优化 分段{s} AI结果数量不匹配 采用原始值");
|
||||||
}
|
}
|
||||||
newCaptionsList.AddRange(resData.Select((text, i) => new SenseVoiceRes()
|
newCaptionsList.AddRange(resData.Select((text, i) => new SenseVoiceRes()
|
||||||
|
|
@ -366,13 +379,12 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
|
||||||
$"完整的课堂标准流程包含以下5个阶段:课程引入/新知讲解/例题精讲/课堂练习/知识总结。\n" +
|
$"完整的课堂标准流程包含以下5个阶段:课程引入/新知讲解/例题精讲/课堂练习/知识总结。\n" +
|
||||||
reviewStr +
|
reviewStr +
|
||||||
$"讲解知识内容的阶段的细分程度到某个知识点的讲解/认识/例题/总结\n" +
|
$"讲解知识内容的阶段的细分程度到某个知识点的讲解/认识/例题/总结\n" +
|
||||||
|
$"不分析课堂作业相关的内容我已经预处理了\n" +
|
||||||
$"初步划分阶段:{keyFrameStr}\n" +
|
$"初步划分阶段:{keyFrameStr}\n" +
|
||||||
$"\n" +
|
$"Stage:判断阶段类型如果内容以解题为主,归类为“例题精讲”;如果涉及新知识讲解,归类为“新知讲解”;以此类推。\n" +
|
||||||
$"内容分析:对每个时间段,提取主要讲解内容:识别关键词(如“例题”“证明”“练习”“总结”)和内容结构。\n" +
|
$"Content:简述单个阶段的核心讲解内容40~150字(如“例题”“证明”“练习”“总结”...), 必须完全基于字幕文本可推断的信息,禁止捏造不存在的内容(硬性条件)。\n" +
|
||||||
$"判断阶段类型:如果内容以解题为主,归类为“例题精讲”;如果涉及新知识讲解,归类为“新知讲解”;以此类推。\n" +
|
$"Theme:理解Content,提炼一个精确的主题(例如,“柯西不等式的基本应用”)。\n" +
|
||||||
$"内容总结:简述该阶段的核心讲解内容40~150字, 必须完全基于字幕文本可推断的信息,禁止捏造不存在的内容(硬性条件)。\n" +
|
$"输出要求:确保阶段划分合理、无重叠、\n" +
|
||||||
$"阶段主题:基于内容总结,提炼一个恰当的主题(例如,“柯西不等式的基本应用”)。\n" +
|
|
||||||
$"输出要求:确保阶段划分合理、无重叠\n" +
|
|
||||||
$"作业布置阶段一般出现在末尾如果有" +
|
$"作业布置阶段一般出现在末尾如果有" +
|
||||||
$"输出格式要求:内容只返回json格式({resFormat})\n" +
|
$"输出格式要求:内容只返回json格式({resFormat})\n" +
|
||||||
$"字幕格式(开始秒:内容|下一段字幕).以下是包含时间的视频字幕文本。\n" +
|
$"字幕格式(开始秒:内容|下一段字幕).以下是包含时间的视频字幕文本。\n" +
|
||||||
|
|
@ -424,7 +436,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
|
||||||
输出格式(仅 JSON):{resFormat}
|
输出格式(仅 JSON):{resFormat}
|
||||||
""";
|
""";
|
||||||
|
|
||||||
var res = await deepSeekClient.ChatAsync<VideoKnowRes>(taskInfo.Id.ToString(), message, "作业布置识别");
|
var res = await deepSeekClient.ChatAsync<VideoKnowRes>(taskInfo.Id.ToString(), message, "作业布置识别", ChatGPTType.Deepseek_Chat, 8000);
|
||||||
if (res is null)
|
if (res is null)
|
||||||
return null;
|
return null;
|
||||||
if (!string.Equals(res.Stage, "作业布置", StringComparison.OrdinalIgnoreCase))
|
if (!string.Equals(res.Stage, "作业布置", StringComparison.OrdinalIgnoreCase))
|
||||||
|
|
@ -575,7 +587,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
|
||||||
$"输出内容只返回json格式为({resFormat})" +
|
$"输出内容只返回json格式为({resFormat})" +
|
||||||
$"以下是试题内容" +
|
$"以下是试题内容" +
|
||||||
$"`{sRes.Result.res.value}`";
|
$"`{sRes.Result.res.value}`";
|
||||||
var resData = await deepSeekClient.ChatAsync<VideoQuestionOSSDto[]>(taskInfo.Id.ToString(), postMessages, "提取试题");
|
var resData = await deepSeekClient.ChatAsync<List<VideoQuestionOSSDto>>(taskInfo.Id.ToString(), postMessages, "提取试题");
|
||||||
//var resData = await chatClient.ChatAsync<VideoQuestionOSSDto[]>(taskInfo.Id.ToString(), postMessages, "提取试题");
|
//var resData = await chatClient.ChatAsync<VideoQuestionOSSDto[]>(taskInfo.Id.ToString(), postMessages, "提取试题");
|
||||||
if (resData is null || resData.Count() == 0)
|
if (resData is null || resData.Count() == 0)
|
||||||
break;
|
break;
|
||||||
|
|
@ -704,8 +716,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
|
||||||
if (questionRes is null) continue;
|
if (questionRes is null) continue;
|
||||||
//处理分段 知识点
|
//处理分段 知识点
|
||||||
List<VideoKonwPoint> insertData = await GetVideoKnow(questionRes, taskInfo, sections, knowledgeInfos);
|
List<VideoKonwPoint> insertData = await GetVideoKnow(questionRes, taskInfo, sections, knowledgeInfos);
|
||||||
if (homework != null)
|
|
||||||
questionRes.Add(homework);
|
|
||||||
//校验结果质量
|
//校验结果质量
|
||||||
var checkRes = await VerifySpanQuality(questionRes, taskInfo, captions, sections, Course_Id);
|
var checkRes = await VerifySpanQuality(questionRes, taskInfo, captions, sections, Course_Id);
|
||||||
|
|
||||||
|
|
@ -715,16 +726,19 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
|
||||||
// 质量复检
|
// 质量复检
|
||||||
if (checkRes != null)
|
if (checkRes != null)
|
||||||
{
|
{
|
||||||
var improved = await ImproveSpanBySuggestion(questionRes, taskInfo, captions, sections, checkRes.Suggestion);
|
var improved = await ImproveSpanBySuggestion(questionRes, taskInfo, captions, sections, "扣分原因 {checkRes.MinusScore} \n 改进意见 {checkRes.Suggestion}");
|
||||||
if (improved != null)
|
if (improved != null)
|
||||||
{
|
{
|
||||||
var improvedCheck = await VerifySpanQuality(improved, taskInfo, captions, sections, Course_Id);
|
var improvedCheck = await VerifySpanQuality(improved, taskInfo, captions, sections, Course_Id);
|
||||||
await redisManager.AddTaskLog(taskInfo.Id, $"==>优化后复检得分=>{improvedCheck.Score}");
|
await redisManager.AddTaskLog(taskInfo.Id, $"==>优化后复检得分=>{improvedCheck.Score}");
|
||||||
await redisManager.AddTaskLog(taskInfo.Id, $"==>优化后扣分原因 {improvedCheck.MinusScore}");
|
await redisManager.AddTaskLog(taskInfo.Id, $"==>优化后扣分原因 {improvedCheck.MinusScore}");
|
||||||
|
|
||||||
if (improvedCheck != null && improvedCheck.Score >= 90)
|
if (improvedCheck != null && improvedCheck.Score >= 90 && improvedCheck.Score > checkRes.Score)
|
||||||
{
|
{
|
||||||
questionRes = improved;
|
questionRes = improved;
|
||||||
|
if (homework != null && (!questionRes.Any(s => s.Stage == StageEnum.作业布置.ToString())))
|
||||||
|
questionRes.Add(homework);
|
||||||
|
|
||||||
insertData = await GetVideoKnow(questionRes, taskInfo, sections, knowledgeInfos);
|
insertData = await GetVideoKnow(questionRes, taskInfo, sections, knowledgeInfos);
|
||||||
await videoKonwPointDB.DeleteAsync(s => s.VideoTaskId == taskInfo.Id);
|
await videoKonwPointDB.DeleteAsync(s => s.VideoTaskId == taskInfo.Id);
|
||||||
await videoTaskStageDB.DeleteAsync(s => s.VideoTaskId == taskInfo.Id);
|
await videoTaskStageDB.DeleteAsync(s => s.VideoTaskId == taskInfo.Id);
|
||||||
|
|
@ -733,9 +747,10 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
|
||||||
Id = s.Key,
|
Id = s.Key,
|
||||||
TagId = s.First().TagId,
|
TagId = s.First().TagId,
|
||||||
CloudSchoolId = s.First().CloudSchoolId,
|
CloudSchoolId = s.First().CloudSchoolId,
|
||||||
StartTime = s.Last().StartTime,
|
StartTime = s.First().StartTime,
|
||||||
EndTime =s.Last().EndTime,
|
EndTime = s.First().EndTime,
|
||||||
KnowSourceTime=s.Last().KnowSourceTime,
|
Content = s.First().Content,
|
||||||
|
TextbookSource = s.First().TextbookSource,
|
||||||
Stage = s.First().Stage,
|
Stage = s.First().Stage,
|
||||||
Theme = s.First().Theme,
|
Theme = s.First().Theme,
|
||||||
VideoTaskId = taskInfo.Id,
|
VideoTaskId = taskInfo.Id,
|
||||||
|
|
@ -744,6 +759,11 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
|
||||||
await videoKonwPointDB.InsertRangeAsync(insertData);
|
await videoKonwPointDB.InsertRangeAsync(insertData);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await redisManager.AddTaskLog(taskInfo.Id, $"==>优化之后的得分降低/得分过低");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ namespace VideoAnalysisCore.AICore.GPT.ChatGPT
|
||||||
stream = true,
|
stream = true,
|
||||||
temperature = 0.2f,
|
temperature = 0.2f,
|
||||||
messages = messageArr,
|
messages = messageArr,
|
||||||
max_completion_tokens=16000,
|
max_completion_tokens= 12288,
|
||||||
};
|
};
|
||||||
|
|
||||||
chatReq.modalities = null;
|
chatReq.modalities = null;
|
||||||
|
|
|
||||||
|
|
@ -143,7 +143,7 @@ namespace VideoAnalysisCore.AICore.SherpaOnnx
|
||||||
throw new Exception("task 音频路径未找到");
|
throw new Exception("task 音频路径未找到");
|
||||||
if (OR is null) Init();
|
if (OR is null) Init();
|
||||||
serviceProvider.GetRequiredService<SherpaVad>()
|
serviceProvider.GetRequiredService<SherpaVad>()
|
||||||
.TaskHandle(new WaveReader(filePath), null, SoundHandle, SherpaVadVersion.silero_vad_v5);
|
.TaskHandle(new WaveReader(filePath), task, SoundHandle, SherpaVadVersion.silero_vad_v5);
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ namespace VideoAnalysisCore.Controllers
|
||||||
private readonly Repository<VideoTask> videoTaskDB;
|
private readonly Repository<VideoTask> videoTaskDB;
|
||||||
private readonly Repository<CourseInfo> courseInfoDB;
|
private readonly Repository<CourseInfo> courseInfoDB;
|
||||||
private readonly Repository<VideoKonwPoint> videoKonwPointDB;
|
private readonly Repository<VideoKonwPoint> videoKonwPointDB;
|
||||||
|
private readonly Repository<VideoTaskStage> videoTaskStageDB;
|
||||||
private readonly Repository<NodePackageInfo> nodePackageInfoDB;
|
private readonly Repository<NodePackageInfo> nodePackageInfoDB;
|
||||||
private readonly Repository<VideoQuestion> videoQuestionDB;
|
private readonly Repository<VideoQuestion> videoQuestionDB;
|
||||||
private readonly Repository<VideoQuestionKonw> videoQuestionKonwDB;
|
private readonly Repository<VideoQuestionKonw> videoQuestionKonwDB;
|
||||||
|
|
@ -42,7 +43,7 @@ namespace VideoAnalysisCore.Controllers
|
||||||
|
|
||||||
public LJZK_Controller(IMapper mp, Repository<NodeSubscription> nodesubscriptionDB,
|
public LJZK_Controller(IMapper mp, Repository<NodeSubscription> nodesubscriptionDB,
|
||||||
Repository<VideoTask> videoTaskDB = null, Repository<VideoKonwPoint> videoKonwPointDB = null
|
Repository<VideoTask> videoTaskDB = null, Repository<VideoKonwPoint> videoKonwPointDB = null
|
||||||
, Repository<NodePackageInfo> nodePackageInfoDB = null, Repository<VideoQuestion> videoQuestionDB = null, Repository<VideoQuestionKonw> videoQuestionKonwDB = null, Repository<CourseInfo> courseInfoDB = null, RedisManager redisManager = null)
|
, Repository<NodePackageInfo> nodePackageInfoDB = null, Repository<VideoQuestion> videoQuestionDB = null, Repository<VideoQuestionKonw> videoQuestionKonwDB = null, Repository<CourseInfo> courseInfoDB = null, RedisManager redisManager = null, Repository<VideoTaskStage> videoTaskStageDB = null)
|
||||||
{
|
{
|
||||||
this.mp = mp;
|
this.mp = mp;
|
||||||
this.nodesubscriptionDB = nodesubscriptionDB;
|
this.nodesubscriptionDB = nodesubscriptionDB;
|
||||||
|
|
@ -53,6 +54,7 @@ namespace VideoAnalysisCore.Controllers
|
||||||
this.videoQuestionKonwDB = videoQuestionKonwDB;
|
this.videoQuestionKonwDB = videoQuestionKonwDB;
|
||||||
this.courseInfoDB = courseInfoDB;
|
this.courseInfoDB = courseInfoDB;
|
||||||
this.redisManager = redisManager;
|
this.redisManager = redisManager;
|
||||||
|
this.videoTaskStageDB = videoTaskStageDB;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -201,27 +203,49 @@ namespace VideoAnalysisCore.Controllers
|
||||||
.ToArrayAsync();
|
.ToArrayAsync();
|
||||||
if (konwArr is null || konwArr.Length == 0)
|
if (konwArr is null || konwArr.Length == 0)
|
||||||
return BadRequest("ÎÞÓÐЧÈÎÎñ·Ö¶Î");
|
return BadRequest("ÎÞÓÐЧÈÎÎñ·Ö¶Î");
|
||||||
|
|
||||||
|
|
||||||
|
var stageArr = await videoTaskStageDB.AsQueryable()
|
||||||
|
.Where(s => s.VideoTaskId == task.Id)
|
||||||
|
.ToArrayAsync();
|
||||||
|
var videoKnowDic = konwArr
|
||||||
|
.GroupBy(s => s.StageId)
|
||||||
|
.ToDictionary(s => s.Key);
|
||||||
|
var videoKnows = stageArr
|
||||||
|
.Select(s => new VideoKnowRes()
|
||||||
|
{
|
||||||
|
Content = s.Content,
|
||||||
|
StartTime = s.StartTime,
|
||||||
|
EndTime = s.EndTime,
|
||||||
|
Theme = s.Theme,
|
||||||
|
StageId = s.Id,
|
||||||
|
KnowPoint = videoKnowDic.ContainsKey(s.Id)
|
||||||
|
? string.Join(',', videoKnowDic[s.Id].Select(x => x.KnowPoint))
|
||||||
|
: string.Empty
|
||||||
|
}).ToArray();
|
||||||
|
|
||||||
var res = new TaskKnowRes()
|
var res = new TaskKnowRes()
|
||||||
{
|
{
|
||||||
TagId = task.TagId,
|
TagId = task.TagId,
|
||||||
Status = task.LastEnum,
|
Status = task.LastEnum,
|
||||||
VideoTaskId = task.Id,
|
VideoTaskId = task.Id,
|
||||||
KnowBlockArr = konwArr
|
KnowBlockArr = stageArr
|
||||||
.GroupBy(s => s.StartTime)
|
|
||||||
.Select(s => new TaskKnowBlock()
|
.Select(s => new TaskKnowBlock()
|
||||||
{
|
{
|
||||||
Id = s.First().Id,
|
Id = s.Id,
|
||||||
Content = s.First().Content,
|
Content = s.Content,
|
||||||
StartTime = s.First().StartTime,
|
StartTime = s.StartTime,
|
||||||
StageId = s.First().StageId,
|
StageId = s.Id,
|
||||||
EndTime = s.First().EndTime,
|
EndTime = s.EndTime,
|
||||||
Theme = s.First().Theme,
|
Theme = s.Theme,
|
||||||
Know = s.Select(x => new TaskKnowInfo()
|
Know = videoKnowDic.ContainsKey(s.Id)
|
||||||
|
? videoKnowDic[s.Id]?.Select(x => new TaskKnowInfo()
|
||||||
{
|
{
|
||||||
Id = x.Id,
|
Id = x.Id,
|
||||||
KnowPoint = x.KnowPoint,
|
KnowPoint = x.KnowPoint,
|
||||||
KnowPointId = x.KnowPointId
|
KnowPointId = x.KnowPointId,
|
||||||
}).ToArray()
|
})?.ToArray()
|
||||||
|
: null
|
||||||
}).ToArray()
|
}).ToArray()
|
||||||
};
|
};
|
||||||
if (task.VideoType == AttachmentsInfoType.¸´Ï°)
|
if (task.VideoType == AttachmentsInfoType.¸´Ï°)
|
||||||
|
|
|
||||||
|
|
@ -33,9 +33,11 @@ namespace VideoAnalysisCore.Controllers
|
||||||
readonly Repository<VideoTask> baseService;
|
readonly Repository<VideoTask> baseService;
|
||||||
readonly Repository<VideoQuestion> videoQuestionDB;
|
readonly Repository<VideoQuestion> videoQuestionDB;
|
||||||
readonly Repository<VideoKonwPoint> videoKonwPointDB;
|
readonly Repository<VideoKonwPoint> videoKonwPointDB;
|
||||||
|
readonly Repository<VideoTaskStage> videoTaskStageDB;
|
||||||
readonly Repository<VideoQuestionKonw> videoQuestionKonwDB;
|
readonly Repository<VideoQuestionKonw> videoQuestionKonwDB;
|
||||||
readonly Repository<TaskLog> taskLogDB;
|
readonly Repository<TaskLog> taskLogDB;
|
||||||
|
|
||||||
|
|
||||||
readonly RedisManager redisManager;
|
readonly RedisManager redisManager;
|
||||||
public readonly SenseVoice senseVoice;
|
public readonly SenseVoice senseVoice;
|
||||||
public readonly FunASRNano funASRNano;
|
public readonly FunASRNano funASRNano;
|
||||||
|
|
@ -43,7 +45,7 @@ namespace VideoAnalysisCore.Controllers
|
||||||
private readonly IMapper mp;
|
private readonly IMapper mp;
|
||||||
public VideoTaskController(Repository<VideoTask> baseService, RedisManager redisManager,
|
public VideoTaskController(Repository<VideoTask> baseService, RedisManager redisManager,
|
||||||
Repository<VideoQuestion> videoQuestionDB,
|
Repository<VideoQuestion> videoQuestionDB,
|
||||||
Repository<VideoQuestionKonw> videoQuestionKonwDB, Repository<VideoKonwPoint> videoKonwPointDB, SenseVoice senseVoice, IMapper mp, Repository<TaskLog> taskLogDB, FunASRNano funASRNano) : base(baseService)
|
Repository<VideoQuestionKonw> videoQuestionKonwDB, Repository<VideoKonwPoint> videoKonwPointDB, SenseVoice senseVoice, IMapper mp, Repository<TaskLog> taskLogDB, FunASRNano funASRNano, Repository<VideoTaskStage> videoTaskStageDB) : base(baseService)
|
||||||
{
|
{
|
||||||
this.baseService = baseService;
|
this.baseService = baseService;
|
||||||
this.redisManager = redisManager;
|
this.redisManager = redisManager;
|
||||||
|
|
@ -54,6 +56,7 @@ namespace VideoAnalysisCore.Controllers
|
||||||
this.mp = mp;
|
this.mp = mp;
|
||||||
this.taskLogDB = taskLogDB;
|
this.taskLogDB = taskLogDB;
|
||||||
this.funASRNano = funASRNano;
|
this.funASRNano = funASRNano;
|
||||||
|
this.videoTaskStageDB = videoTaskStageDB;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -370,17 +373,23 @@ namespace VideoAnalysisCore.Controllers
|
||||||
var konwArr = await videoKonwPointDB.AsQueryable()
|
var konwArr = await videoKonwPointDB.AsQueryable()
|
||||||
.Where(s => s.VideoTaskId == nowTask.Id)
|
.Where(s => s.VideoTaskId == nowTask.Id)
|
||||||
.ToArrayAsync();
|
.ToArrayAsync();
|
||||||
|
var stageArr = await videoTaskStageDB.AsQueryable()
|
||||||
var videoKnows = konwArr
|
.Where(s => s.VideoTaskId == nowTask.Id)
|
||||||
.GroupBy(s => s.StartTime)
|
.ToArrayAsync();
|
||||||
|
var videoKnowDic = konwArr
|
||||||
|
.GroupBy(s => s.StageId)
|
||||||
|
.ToDictionary(s => s.Key);
|
||||||
|
var videoKnows = stageArr
|
||||||
.Select(s => new VideoKnowRes()
|
.Select(s => new VideoKnowRes()
|
||||||
{
|
{
|
||||||
Content = s.First().Content,
|
Content = s.Content,
|
||||||
StartTime = s.First().StartTime,
|
StartTime = s.StartTime,
|
||||||
EndTime = s.First().EndTime,
|
EndTime = s.EndTime,
|
||||||
Theme = s.First().Theme,
|
Theme = s.Theme,
|
||||||
StageId = s.First().StageId,
|
StageId = s.Id,
|
||||||
KnowPoint = string.Join(',', s.Select(x => x.KnowPoint))
|
KnowPoint = videoKnowDic.ContainsKey(s.Id)
|
||||||
|
? string.Join(',', videoKnowDic[s.Id].Select(x => x.KnowPoint))
|
||||||
|
: string.Empty
|
||||||
}).ToArray();
|
}).ToArray();
|
||||||
if (nowTask.VideoType == AttachmentsInfoType.复习)
|
if (nowTask.VideoType == AttachmentsInfoType.复习)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -65,9 +65,13 @@ namespace VideoAnalysisCore.Model
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? KnowPointId { get; set; }
|
public string? KnowPointId { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 知识点来源 视频秒
|
/// 知识点占比权重
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public float KnowSourceTime { get; set; }
|
public float? KnowPointWeight { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 知识点来源
|
||||||
|
/// </summary>
|
||||||
|
public string KnowSource { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 内容总结[不写入数据库]
|
/// 内容总结[不写入数据库]
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -84,5 +88,11 @@ namespace VideoAnalysisCore.Model
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(IsNullable = true)]
|
[SugarColumn(IsNullable = true)]
|
||||||
public long? CloudSchoolId { get; set; }
|
public long? CloudSchoolId { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 教材来源
|
||||||
|
/// <para> 课本/试卷/挹青苑 ...</para>
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(IsIgnore = true)]
|
||||||
|
public virtual string? TextbookSource { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,9 +54,9 @@ namespace VideoAnalysisCore.Model
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? Theme { get; set; }
|
public string? Theme { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 知识点来源 视频秒
|
/// 知识点来源 视频秒,来源原因
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public float KnowSourceTime { get; set; }
|
public string Content { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 课程阶段
|
/// 课程阶段
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -68,5 +68,11 @@ namespace VideoAnalysisCore.Model
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(IsNullable = true)]
|
[SugarColumn(IsNullable = true)]
|
||||||
public long? CloudSchoolId { get; set; }
|
public long? CloudSchoolId { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 教材来源
|
||||||
|
/// <para> 课本/试卷/挹青苑 ...</para>
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(IsNullable = true)]
|
||||||
|
public virtual string? TextbookSource { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue