parent
d433d84d46
commit
f943c4fec4
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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 />
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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,9 +68,7 @@ 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()
|
foreach (var item in taskArr)
|
||||||
// .PostAsJsonAsync(AppCommon.Config.Subsystem.蓝鲸智库.APIUrl + "/api/callback/platform/videosAnalyze", postData);
|
|
||||||
foreach (var item in taskArr)
|
|
||||||
{
|
{
|
||||||
HttpResponseMessage responseMessage = null;
|
HttpResponseMessage responseMessage = null;
|
||||||
try
|
try
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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; }
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue