优化 视频试题AI分析试题识别精准度

修改 蓝鲸字库 请求流程
This commit is contained in:
小肥羊 2025-06-12 16:12:01 +08:00
parent d433d84d46
commit f943c4fec4
14 changed files with 150 additions and 114 deletions

View File

@ -34,6 +34,7 @@ namespace Learn.VideoAnalysis.API
//初始化 插件 //初始化 插件
builder.Configuration.AddAppConfig(args); builder.Configuration.AddAppConfig(args);
builder.Services.AddHttpClient();
builder.Services.AddSqlSugarExpand(); builder.Services.AddSqlSugarExpand();
builder.Services.AddRedisExpand(); builder.Services.AddRedisExpand();
builder.Services.AddCoravel(); builder.Services.AddCoravel();

View File

@ -27,7 +27,7 @@
<h3>问题: <span class="kSpan">@q.StartTime 秒</span></h3> <h3>问题: <span class="kSpan">@q.StartTime 秒</span></h3>
<div class="kSpan">@q.TopicStem</div> <div class="kSpan">@q.TopicStem</div>
<div >@q.Question</div> <div >@q.Question</div>
<img style="text-align:center" src="@q.ImageUrl" width="320" height="180" /> <img style="text-align:center" src="@q.PPTImageUrl" width="320" height="180" />
</div> </div>
<br /> <br />
} }

View File

@ -22,6 +22,14 @@
"FFmpeg": { "FFmpeg": {
" TimeSlice": 600 " TimeSlice": 600
}, },
"AliyunOSS": {
"AccessKeyId": "LTAI5tDC6p9h747B7FHbgwkH",
"AccessKeySecret": "vRKgmbp1LB05LaGOjh3ZrZxbHSLYLF",
"BucketDomain": "https://learn-videoanalysis.oss-cn-chengdu.aliyuncs.com",
"Region": "cn-chengdu",
"BucketName": "learn-videoanalysis",
"EndPoint": "oss-cn-chengdu.aliyuncs.com" //
},
"DB": { "DB": {
//"ConnectionString": "AllowLoadLocalInfile=true;Server=10.255.255.3;Port=3306;Database=learn.videoanalysis;User ID=marking;Password=qwe123!@#;CharSet=utf8mb4;pooling=true;SslMode=None", //"ConnectionString": "AllowLoadLocalInfile=true;Server=10.255.255.3;Port=3306;Database=learn.videoanalysis;User ID=marking;Password=qwe123!@#;CharSet=utf8mb4;pooling=true;SslMode=None",
"ConnectionString": "AllowLoadLocalInfile=true;Server=rm-2vc20nd3d11g0oh6g2o.rwlb.cn-chengdu.rds.aliyuncs.com;User ID=marking;Password=poiuytPOIUYT098765)(*&^%;Port=3306;Database=learn.videoanalysis;CharSet=utf8mb4;pooling=true;SslMode=None", "ConnectionString": "AllowLoadLocalInfile=true;Server=rm-2vc20nd3d11g0oh6g2o.rwlb.cn-chengdu.rds.aliyuncs.com;User ID=marking;Password=poiuytPOIUYT098765)(*&^%;Port=3306;Database=learn.videoanalysis;CharSet=utf8mb4;pooling=true;SslMode=None",

View File

@ -68,7 +68,7 @@ namespace VideoAnalysisCore.AICore.FFMPGE
RedisExpand.SetTaskProgress(task, "Frame=>50%"); RedisExpand.SetTaskProgress(task, "Frame=>50%");
Image<Rgb24> prevFrame = null; Image<Rgb24> prevFrame = null;
var keyFrames = new List<int>(); var keyFrames = new List<int>(5);
foreach (var frameFile in frameFiles) foreach (var frameFile in frameFiles)
{ {
using (var currFrame = Image.Load<Rgb24>(frameFile)) using (var currFrame = Image.Load<Rgb24>(frameFile))

View File

@ -19,6 +19,7 @@ using FFmpeg.NET.Services;
using Aliyun.OSS; using Aliyun.OSS;
using Yitter.IdGenerator; using Yitter.IdGenerator;
using VideoAnalysisCore.Common.Expand; using VideoAnalysisCore.Common.Expand;
using System.Collections.Generic;
namespace VideoAnalysisCore.AICore.GPT.DeepSeek namespace VideoAnalysisCore.AICore.GPT.DeepSeek
{ {
@ -57,18 +58,9 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
/// 获取内容对应的章节 /// 获取内容对应的章节
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
private async Task<List<VideoKonwPoint>> GetVideoKnow(List<VideoKnowRes> questionRes, VideoTask taskInfo, string sections, int course_Id) private async Task<List<VideoKonwPoint>> GetVideoKnow(List<VideoKnowRes> questionRes, VideoTask taskInfo,
string sections, List<KnowledgeInfo> knowledgeInfos)
{ {
var know = await knowledgeInfoDB.GetFirstAsync(s => s.Course_Id == course_Id && s.Name == sections);
if (know is null)
throw new Exception("未能找到对应知识点=>" + sections);
var subject = taskInfo.Subject.ToString();
var kInfo = await knowledgeInfoDB.GetByIdAsync(know.Parent_Id);
var knowledgeInfos = await knowledgeInfoDB.AsQueryable()
.ToChildListAsync(s => s.Parent_Id, kInfo.Parent_Id == 0 ? kInfo.Id : kInfo.Parent_Id);
var knows = string.Join(',', knowledgeInfos.Select(s => s.Id + "|" + s.Name)); var knows = string.Join(',', knowledgeInfos.Select(s => s.Id + "|" + s.Name));
var knowDic = knowledgeInfos var knowDic = knowledgeInfos
.OrderBy(s => s.Id) .OrderBy(s => s.Id)
@ -79,7 +71,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
var thems = JsonSerializer.Serialize(questionRes.Adapt<VideoKnowQueryDto[]>());// string.Join(',', questionRes.Select(s => s.StartTime + "->" + s.Theme)); var thems = JsonSerializer.Serialize(questionRes.Adapt<VideoKnowQueryDto[]>());// string.Join(',', questionRes.Select(s => s.StartTime + "->" + s.Theme));
var checkResFormat1 = """[{"StartTime":开始秒(number),"KnowPoint":知识点名称(string),"KnowPointId":知识点Id(string)}]"""; var checkResFormat1 = """[{"StartTime":开始秒(number),"KnowPoint":知识点名称(string),"KnowPointId":知识点Id(string)}]""";
var knowMessages = var knowMessages =
$"我针对{subject}课堂授课视频分析出了视频的授课阶段片段。" + $"我针对{taskInfo.Subject}课堂授课视频分析出了视频的授课阶段片段。" +
$"现在需要你通过每个片段的内容总结来分配正确的知识点(单个片段允许多个知识点用逗号','分割)。" + $"现在需要你通过每个片段的内容总结来分配正确的知识点(单个片段允许多个知识点用逗号','分割)。" +
$"这是我的分段 {thems}。" + $"这是我的分段 {thems}。" +
$"课堂内容与{sections}章节相关" + $"课堂内容与{sections}章节相关" +
@ -136,7 +128,6 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
&& (s.Depth == 3 && (s.Depth == 3
|| s.Depth == 2)) || s.Depth == 2))
.Select(s => s.Name).ToArrayAsync(); .Select(s => s.Name).ToArrayAsync();
string title = taskInfo.MediaName;
var captionsArr = JsonSerializer.Deserialize<SenseVoiceRes[]>(taskInfo.Captions); var captionsArr = JsonSerializer.Deserialize<SenseVoiceRes[]>(taskInfo.Captions);
var fileNameResFormat = "{授课章节: string|null}"; var fileNameResFormat = "{授课章节: string|null}";
@ -378,22 +369,27 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
/// 提取试题 /// 提取试题
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
private async Task<SenseVoiceRes[]> AnalysisVideoQuestions(VideoTask taskInfo) private async Task<SenseVoiceRes[]> AnalysisVideoQuestions(VideoTask taskInfo, List<KnowledgeInfo> knowledgeInfos)
{ {
Console.WriteLine(DateTime.Now + $"=>{taskInfo.Id} 提取试题"); Console.WriteLine(DateTime.Now + $"=>{taskInfo.Id} 提取试题");
if (taskInfo is null || string.IsNullOrEmpty(taskInfo.PPTKeyFrame)) if (taskInfo is null || string.IsNullOrEmpty(taskInfo.PPTKeyFrame))
return null; return null;
var farmeArr = JsonSerializer.Deserialize<int[]>(taskInfo.PPTKeyFrame); var farmeArr = JsonSerializer.Deserialize<int[]>(taskInfo.PPTKeyFrame);
var knowArrStr = string.Join(',', knowledgeInfos.Select(s => s.Id + "|" + s.Name));
var videoKnowArr = await videoKonwPointDB.GetListAsync(s => s.VideoTaskId == taskInfo.Id); var videoKnowArr = await videoKonwPointDB.GetListAsync(s => s.VideoTaskId == taskInfo.Id);
var videoKnowDic = knowledgeInfos
.GroupBy(s => s.Id)
.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+5 >= s.StartTime && item+5 <= s.EndTime) .Where(s => item+30 >= s.StartTime && item <= s.EndTime)
.ToArray(); .ToArray();
if (knowInfoArr is null || knowInfoArr.Count() ==0) if (knowInfoArr is null || knowInfoArr.Count() ==0)
return null; continue;
var tryCount = 50; var tryCount = 50;
while (tryCount>1) while (tryCount>1)
{ {
@ -409,20 +405,24 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
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 =
$"我将提供一段内容是md格式的试题内容字符串。" + $"我将提供一段内容是Markdown格式的试题。" +
$"请提取出其中的试题内容试,题干以及每个试题的问题。并且为每个试题关联上在我限定范围内的知识点(多个则用逗号分割)。" + $"请提取出其中有效的试题内容(包括 题干,公式试题内提出的问题 )。" +
$"知识点格式(json格式)范围[{knowArr}]。" + $"为每个问题关联上限定范围内的知识点(多个则用逗号分割),知识点格式 (知识点Id|知识点名称)知识点范围[{knowArrStr}]。" +
$"排除不是试题内容的文字,优化公式排版并且去除题号,但不要修改latex数学公式。" + $"排除不是试题内容的文字,优化试题排版并且去除题号,尽量保留latex数学公式。" +
$"如果存在多道题,则需要拆分成为多个试题对象!" + $"如果存在多道题,则需要拆分成为多个试题对象!" +
$"试题的类型约束在 填空题/判断题/选择题/解答题 范围内。" + $"试题的类型约束在 填空题/判断题/选择题/解答题/填空题 范围内。" +
$"请检查我提供的字符串内容,如不包含问题试题则返回`[]`" + $"如果存在题干中存在下划线则试题的题型应该是填空题。" +
$"请检查我提供的字符串内容,如果不能识别知识点则不处理知识点,如不包含问题试题则返回`[]`" +
$"输出内容只返回json格式为({resFormat})" + $"输出内容只返回json格式为({resFormat})" +
$"以下是试题内容" + $"以下是试题内容" +
$"`{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, "提取试题");
if(resData is null || resData.Count()==0)
break;
foreach (var q in resData) foreach (var q in resData)
{ {
var TopicId = YitIdHelper.NextId(); var TopicId = YitIdHelper.NextId();
@ -436,16 +436,22 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
vq.StageId = knowInfoArr.First().StageId; vq.StageId = knowInfoArr.First().StageId;
vq.Question = qt.Question; vq.Question = qt.Question;
vq.TopicId = TopicId; vq.TopicId = TopicId;
vq.Type = q.Type;
if(string.IsNullOrEmpty(qt.KnowPointId))
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);
if(!tryOk || !videoKnowDic.ContainsKey(kidd))
continue;//跳过未识别知识点
insertQuestionKonw.Add(new VideoQuestionKonw() insertQuestionKonw.Add(new VideoQuestionKonw()
{ {
KnowPoint = knowInfoArr.First(s => s.KnowPointId == kid).KnowPoint, KnowPoint = videoKnowDic[kidd].Name,
KnowPointId = kid, KnowPointId = kid,
StageId = q.StageId, StageId = q.StageId,
VideoTaskId = q.VideoTaskId, VideoTaskId = vq.VideoTaskId,
VideoQuestionId = q.Id, VideoQuestionId = vq.Id,
}); });
} }
} }
@ -467,7 +473,6 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
await videoQuestionKonwDB.AsDeleteable() await videoQuestionKonwDB.AsDeleteable()
.Where(s => s.VideoTaskId == taskInfo.Id) .Where(s => s.VideoTaskId == taskInfo.Id)
.ExecuteCommandAsync(); .ExecuteCommandAsync();
await videoQuestionDB.InsertRangeAsync(insertData.Adapt<VideoQuestion[]>()); await videoQuestionDB.InsertRangeAsync(insertData.Adapt<VideoQuestion[]>());
await videoQuestionKonwDB.InsertRangeAsync(insertQuestionKonw); await videoQuestionKonwDB.InsertRangeAsync(insertQuestionKonw);
@ -502,6 +507,14 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
var captionsArr = JsonSerializer.Deserialize<SenseVoiceRes[]>(taskInfo.Captions); var captionsArr = JsonSerializer.Deserialize<SenseVoiceRes[]>(taskInfo.Captions);
//处理视频授课章节 //处理视频授课章节
var sections = await GetSections(taskInfo, Course_Id); var sections = await GetSections(taskInfo, Course_Id);
var know = await knowledgeInfoDB.GetFirstAsync(s => s.Course_Id == Course_Id && s.Name == sections);
if (know is null)
throw new Exception("未能找到对应知识点=>" + sections);
var kInfo = await knowledgeInfoDB.GetByIdAsync(know.Parent_Id);
var knowledgeInfos = await knowledgeInfoDB.AsQueryable()
.ToChildListAsync(s => s.Parent_Id, kInfo.Parent_Id == 0 ? kInfo.Id : kInfo.Parent_Id);
//AI优化字幕 //AI优化字幕
captionsArr = await OptimizeSubtitles(taskInfo, captionsArr, sections); captionsArr = await OptimizeSubtitles(taskInfo, captionsArr, sections);
//合并字幕 //合并字幕
@ -516,7 +529,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
if (questionRes.Count == 0) continue; if (questionRes.Count == 0) continue;
//处理分段 知识点 //处理分段 知识点
var insertData = await GetVideoKnow(questionRes, taskInfo, sections, Course_Id); 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);
@ -544,7 +557,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
.HMSetAsync(RedisExpandKey.Task(task), "VideoKnows", questionRes); .HMSetAsync(RedisExpandKey.Task(task), "VideoKnows", questionRes);
if (taskInfo.VideoType == AttachmentsInfoType.Review) if (taskInfo.VideoType == AttachmentsInfoType.Review)
await AnalysisVideoQuestions(taskInfo); await AnalysisVideoQuestions(taskInfo, knowledgeInfos);
RedisExpand.InsertChannel(RedisChannelEnum.EndTask, task); RedisExpand.InsertChannel(RedisChannelEnum.EndTask, task);
return null; return null;

View File

@ -127,7 +127,7 @@ namespace VideoAnalysisCore.Common
//获取资源文件 地址 //获取资源文件 地址
var taskInfo = await videoTaskDB.AsQueryable() var taskInfo = await videoTaskDB.AsQueryable()
.Where(s => s.Id == taskId).FirstAsync(); .Where(s => s.Id == taskId).FirstAsync();
if (taskInfo is null || string.IsNullOrEmpty(taskInfo.MediaName) || taskInfo.MediaName.Contains("教研")) if (taskInfo is null )
throw new Exception($"任务为null/是教研视频/没有视频课程名称"); throw new Exception($"任务为null/是教研视频/没有视频课程名称");
var fileUrl = taskInfo.MediaUrl; var fileUrl = taskInfo.MediaUrl;
if (string.IsNullOrEmpty(fileUrl)) if (string.IsNullOrEmpty(fileUrl))

View File

@ -88,10 +88,14 @@ namespace VideoAnalysisCore.Common.Expand
{ {
try try
{ {
var path = item.VideoTaskId.ToString() + "/" + Path.GetFileName(item.FilePath); var isDebug = false;
#if DEBUG
isDebug = true;
#endif
var path = (isDebug ?"debug/":string.Empty) + item.VideoTaskId.ToString() + "/" + Path.GetFileName(item.FilePath);
if (cached.Contains(item.FilePath)) if (cached.Contains(item.FilePath))
{ {
item.ImageUrl = AppCommon.Config.AliyunOSS.BucketDomain + "/" + path; item.PPTImageUrl = AppCommon.Config.AliyunOSS.BucketDomain + "/" + path;
continue; continue;
} }
using var file = File.OpenRead(item.FilePath); using var file = File.OpenRead(item.FilePath);
@ -100,7 +104,7 @@ namespace VideoAnalysisCore.Common.Expand
AppCommon.Config.AliyunOSS.BucketName, AppCommon.Config.AliyunOSS.BucketName,
path, path,
file); file);
item.ImageUrl = AppCommon.Config.AliyunOSS.BucketDomain + "/" + path; item.PPTImageUrl = AppCommon.Config.AliyunOSS.BucketDomain + "/" + path;
cached.Add(item.FilePath); cached.Add(item.FilePath);
continue; continue;
} }

View File

@ -46,18 +46,24 @@ namespace VideoAnalysisCore.Controllers.Dto
} }
public class NodePackageReq public class NodePackageReq
{ {
/// <summary>
/// 素材Id 需要返回给我的参数
/// </summary>
public long MaterialId { get; set; }
/// <summary> /// <summary>
/// 录播结构目录节点编号 /// 文件Id 需要返回给我的参数
/// </summary> /// </summary>
[Required(ErrorMessage = "目录节点编号是必填项")] public long AttachmentId { get; set; }
public long NodeId { get; set; }
/// <summary> /// <summary>
/// 科目类型 /// 需要返回给我的参数
/// </summary> /// </summary>
[Required(ErrorMessage = "科目类型是必填项")] public string VideoCode { get; set; }
public SubjectEnum SubjectType { get; set; } /// <summary>
/// 视频地址
/// </summary>
public string VideoUrl { get; set; }
/// <summary> /// <summary>
/// 任务类型 /// 任务类型
@ -66,10 +72,33 @@ namespace VideoAnalysisCore.Controllers.Dto
public TaskTypeEnum TaskType { get; set; } public TaskTypeEnum TaskType { get; set; }
/// <summary> /// <summary>
/// 视频列表 /// 课程类型 0=新课 3=复习 4= 活动 5=班会 7=其他资料
/// </summary> /// </summary>
[Required(ErrorMessage = "文件数量是必填项")] public AttachmentsInfoType CourseType { get; set; }
public List<StructurePageContentAnalyzeItem> AnalyzeItems { get; set; } /// <summary>
/// 视频类型 PPT课件 = 1, 摄像头 = 2
/// </summary>
public int VideoType { get; set; }
/// <summary>
/// 分析完成后的回调地址
/// </summary>
public string CallBackUrl { get; set; }
/// <summary>
/// 请求区域 回调的时候 需要把这个添加到Headers里面 Key=Area value=Area的值
/// </summary>
public string Area { get; set; }
/// <summary>
/// 请求区域 回调的时候 需要把这个添加到Headers里面 Key=HostIP value=HostIP的值
/// </summary>
public string HostIP { get; set; }
/// <summary>
/// 科目类型
/// </summary>
[Required(ErrorMessage = "科目类型是必填项")]
public SubjectEnum SubjectType { get; set; }
} }
/// <summary> /// <summary>

View File

@ -45,79 +45,52 @@ namespace VideoAnalysisCore.Controllers
} }
/// <summary>
/// 蓝鲸智库_添加文件节点监控
/// </summary>
/// <param name="req">请求体</param>
/// <returns></returns>
[HttpPost(Name = "NodeSubscription")]
[NonAction, Obsolete]
public async Task<IActionResult> NodeSubscription(NodeMonitoringReq req)
{
if (req is null || req.NodeId == 0)
return BadRequest("无效的提交数据");
if (nodesubscriptionDB.IsAny(s => s.NodeId == req.NodeId))
return BadRequest("重复添加了节点监控任务" + req.NodeId);
var res = await nodesubscriptionDB.InsertReturnEntityAsync(new NodeSubscription()
{
NodeId = req.NodeId,
TaskType = req.Type ?? default,
Subject = req.Subject ?? default,
});
return Ok(res);
}
/// <summary> /// <summary>
/// 蓝鲸智库_文件包订阅 /// 蓝鲸智库_文件包订阅
/// </summary> /// </summary>
/// <param name="req">请求体</param> /// <param name="reqArr">请求体</param>
/// <returns></returns> /// <returns></returns>
[HttpPost(Name = "NodePackage")] [HttpPost(Name = "NodePackage")]
public async Task<IActionResult> NodePackage(NodePackageReq req) public async Task<IActionResult> NodePackage(NodePackageReq[] reqArr)
{ {
Console.WriteLine($"{DateTime.Now} 文件包订阅请求 req=" + JsonSerializer.Serialize(req)); Console.WriteLine($"{DateTime.Now} 文件包订阅请求 req=" + JsonSerializer.Serialize(reqArr));
if (req.AnalyzeItems is null || req.AnalyzeItems.Count() == 0) if (reqArr is null || reqArr.Count() == 0)
return BadRequest("无效视频列表数据"); return BadRequest("无效视频列表数据");
var videos = new List<VideoTask>(req.AnalyzeItems.Count); var videos = new List<VideoTask>(reqArr.Count());
var nodePackages = new List<NodePackageInfo>(req.AnalyzeItems.Count); var nodePackages = new List<NodePackageInfo>(reqArr.Count());
var videoIdArr = videoTaskDB.AsQueryable().Select(v => v.TagId).Distinct().ToArray(); var videoIdArr = videoTaskDB.AsQueryable().Select(v => v.TagId).Distinct().ToArray();
foreach (var s in req.AnalyzeItems) foreach (var s in reqArr)
{ {
var np = new NodePackageInfo() var np = new NodePackageInfo()
{ {
VideoCode = s.VideoCode, VideoCode = s.VideoCode,
AttachmentsInfoType = s.AttachmentsInfoType,
MaterialId = s.MaterialId, MaterialId = s.MaterialId,
StructurePageContentId = s.StructurePageContentId, AttachmentId = s.AttachmentId,
VideoName = s.VideoName, TaskType = s.TaskType,
NodeId = req.NodeId, SubjectType = s.SubjectType,
TaskType = req.TaskType,
SubjectType = req.SubjectType,
VideoUrl =s.VideoUrl, VideoUrl =s.VideoUrl,
CourseType = s.CourseType,
CallBackUrl=s.CallBackUrl, CallBackUrl=s.CallBackUrl,
Area = s.Area,
HostIP = s.HostIP,
}; };
nodePackages.Add(np); nodePackages.Add(np);
if (s.AttachmentsInfoType == AttachmentsInfoType.PPT)
continue;
if (videoIdArr.Contains(s.VideoCode)) if (videoIdArr.Contains(s.VideoCode))
continue; continue;
var pptInfo = req.AnalyzeItems //获取ppt videoCode //todo获取ppt videoCode
.FirstOrDefault(x => x.AttachmentsInfoType == AttachmentsInfoType.PPT var pptCode = "todo获取ppt videoCode";
&& s.StructurePageContentId == x.StructurePageContentId);
var pptCode = pptInfo?.VideoCode ?? (pptInfo?.VideoUrl??string.Empty);
videos.Add(new VideoTask() videos.Add(new VideoTask()
{ {
Id = YitIdHelper.NextId(), Id = YitIdHelper.NextId(),
ComeFrom = "127.0.0.1", ComeFrom = "127.0.0.1",
ApiToken = "", ApiToken = "",
Type = req.TaskType, Type = s.TaskType,
Subject = req.SubjectType, Subject = s.SubjectType,
TagId = s.VideoCode, TagId = s.VideoCode,
MediaUrl =s.VideoUrl, MediaUrl =s.VideoUrl,
MediaName = s.VideoName,
PPTVideoCode = pptCode, PPTVideoCode = pptCode,
VideoType =s.AttachmentsInfoType VideoType =s.CourseType
}); });
} }
await nodePackageInfoDB.InsertRangeAsync(nodePackages); await nodePackageInfoDB.InsertRangeAsync(nodePackages);

View File

@ -8,7 +8,9 @@ using System.Net;
using System.Net.Http.Json; using System.Net.Http.Json;
using System.Reflection; using System.Reflection;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Security.Policy;
using System.Text; using System.Text;
using System.Text.Json;
using System.Threading.Tasks; using System.Threading.Tasks;
using UserCenter.Model.Enum; using UserCenter.Model.Enum;
using VideoAnalysisCore.Common; using VideoAnalysisCore.Common;
@ -31,6 +33,7 @@ namespace VideoAnalysisCore.Job
private readonly Repository<NodePackageInfo> nodePackageInfoDB; private readonly Repository<NodePackageInfo> nodePackageInfoDB;
private readonly Repository<Attachments> attachmentsDB; private readonly Repository<Attachments> attachmentsDB;
private readonly Repository<VideoTask> videoTaskDB; private readonly Repository<VideoTask> videoTaskDB;
private readonly IHttpClientFactory _clientFactory;
public NodePackageJob(Repository<Attachments> videoTaskDB, public NodePackageJob(Repository<Attachments> videoTaskDB,
Repository<NodePackageInfo> nodePackageInfoDB, Repository<VideoTask> videotaskDB) Repository<NodePackageInfo> nodePackageInfoDB, Repository<VideoTask> videotaskDB)
{ {
@ -65,8 +68,6 @@ namespace VideoAnalysisCore.Job
Console.WriteLine($"{DateTime.Now} 执行=>文件包任务 任务回调 数量{postData.Count} ..."); Console.WriteLine($"{DateTime.Now} 执行=>文件包任务 任务回调 数量{postData.Count} ...");
if (postData.Count() == 0) if (postData.Count() == 0)
return; return;
//var responseMessage = await new HttpClient()
// .PostAsJsonAsync(AppCommon.Config.Subsystem.蓝鲸智库.APIUrl + "/api/callback/platform/videosAnalyze", postData);
foreach (var item in taskArr) foreach (var item in taskArr)
{ {
HttpResponseMessage responseMessage = null; HttpResponseMessage responseMessage = null;
@ -75,8 +76,14 @@ namespace VideoAnalysisCore.Job
var postUrl = !string.IsNullOrWhiteSpace(item.CallBackUrl) var postUrl = !string.IsNullOrWhiteSpace(item.CallBackUrl)
? item.CallBackUrl ? item.CallBackUrl
: AppCommon.Config.Subsystem..APIUrl + "/api/callback/platform/videosAnalyze"; : AppCommon.Config.Subsystem..APIUrl + "/api/callback/platform/videosAnalyze";
responseMessage = await new HttpClient()
.PostAsJsonAsync(postUrl, postData); var apiClent = _clientFactory.CreateClient();
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");
responseMessage = await apiClent.SendAsync(request);
if (responseMessage.IsSuccessStatusCode) if (responseMessage.IsSuccessStatusCode)
{ {
var res = await responseMessage.Content.ReadAsStringAsync(); var res = await responseMessage.Content.ReadAsStringAsync();

View File

@ -92,7 +92,6 @@ namespace VideoAnalysisCore.Job
Tag = item.NodeId.ToString(), Tag = item.NodeId.ToString(),
TagId = s.VideoCode, TagId = s.VideoCode,
MediaUrl = string.Empty, MediaUrl = string.Empty,
MediaName = s.Name
}); });
} }
var maxId = data.Max(s => s.Id); var maxId = data.Max(s => s.Id);

View File

@ -30,18 +30,9 @@ namespace VideoAnalysisCore.Model
[SugarColumn(Length = 32)] [SugarColumn(Length = 32)]
public string VideoCode { get; set; } public string VideoCode { get; set; }
/// <summary> /// <summary>
/// 视频文件名称 /// 文件Id 需要返回给我的参数
/// </summary> /// </summary>
[SugarColumn(Length = 32)] public long AttachmentId { get; set; }
public string VideoName { get; set; }
/// <summary>
/// 录播结构目录节点编号
/// </summary>
public long NodeId { get; set; }
/// <summary>
/// 录播内容编号
/// </summary>
public long StructurePageContentId { get; set; }
/// <summary> /// <summary>
/// 素材ID /// 素材ID
/// </summary> /// </summary>
@ -49,7 +40,7 @@ namespace VideoAnalysisCore.Model
/// <summary> /// <summary>
/// 内容类型 /// 内容类型
/// </summary> /// </summary>
public AttachmentsInfoType AttachmentsInfoType { get; set; } public AttachmentsInfoType CourseType { get; set; }
/// <summary> /// <summary>
/// 科目类型 /// 科目类型
@ -80,8 +71,17 @@ namespace VideoAnalysisCore.Model
/// <summary> /// <summary>
/// 通知回调地址 /// 通知回调地址
/// </summary> /// </summary>
[SugarColumn(Length = 500)] [SugarColumn(Length = 500)]
public string CallBackUrl { get; set; } public string CallBackUrl { get; set; }
/// <summary>
/// 请求区域
/// <para>回调添加到Headers</para>
/// </summary>
public string Area { get; set; }
/// <summary>
/// 请求区域
/// <para>回调添加到Headers</para>
/// </summary>
public string HostIP { get; set; }
} }
} }

View File

@ -39,10 +39,10 @@ namespace VideoAnalysisCore.Model
public long TopicId { get; set; } public long TopicId { get; set; }
/// <summary> /// <summary>
/// 地址 /// PPT切图地址
/// </summary> /// </summary>
[SugarColumn(Length =100)] [SugarColumn(Length =100)]
public string? ImageUrl { get; set; } public string? PPTImageUrl { get; set; }
/// <summary> /// <summary>
/// 题干 /// 题干
/// </summary> /// </summary>
@ -53,6 +53,12 @@ namespace VideoAnalysisCore.Model
/// </summary> /// </summary>
public string? Question { get; set; } public string? Question { get; set; }
/// <summary> /// <summary>
/// 试题类型
/// <para>[填空题/判断题/选择题/解答题]</para>
/// </summary>
[SugarColumn(Length = 10,IsNullable =true)]
public string? Type { get; set; }
/// <summary>
/// 试题开始时间 /// 试题开始时间
/// </summary> /// </summary>
public int StartTime { get; set; } public int StartTime { get; set; }

View File

@ -28,10 +28,6 @@ namespace VideoAnalysisCore.Model
/// </summary> /// </summary>
public string MediaUrl { get; set; } = string.Empty; public string MediaUrl { get; set; } = string.Empty;
/// <summary> /// <summary>
/// 媒体文件名称
/// </summary>
public string MediaName { get; set; } = string.Empty;
/// <summary>
/// 下载后本地媒体目录 /// 下载后本地媒体目录
/// </summary> /// </summary>
public string LocalMediaPath { get; set; } = string.Empty; public string LocalMediaPath { get; set; } = string.Empty;