Compare commits

...

3 Commits

Author SHA1 Message Date
小肥羊 ad0f415ef6 接入 oss
调试 simpLetex API
2025-05-27 17:59:53 +08:00
小肥羊 2d1c3de69b 新增 视频任务[视频类型]字段 2025-05-26 17:59:32 +08:00
小肥羊 8fd3d4ef4b 优化 AI字幕优化提示词 2025-05-22 17:16:08 +08:00
21 changed files with 348 additions and 71 deletions

View File

@ -66,6 +66,7 @@ namespace Learn.VideoAnalysis
builder.Services.AddSimpleTexOcrClient(); builder.Services.AddSimpleTexOcrClient();
builder.Services.AddDownloadFileExpand(); builder.Services.AddDownloadFileExpand();
builder.Services.AddAlibabaCloudVod(); builder.Services.AddAlibabaCloudVod();
builder.Services.AddAliyunOSS();
builder.Services.AddRedisExpand(); builder.Services.AddRedisExpand();
builder.Services.AddSpeakerAI(); builder.Services.AddSpeakerAI();
builder.Services.AddCoravel(); builder.Services.AddCoravel();

View File

@ -58,13 +58,21 @@
"DB": { "DB": {
"ConnectionString": "AllowLoadLocalInfile=true;Server=192.168.2.9;User ID=root;Password=qwe123!@#;Port=3306;Database=learn.videoanalysis;CharSet=utf8mb4;pooling=true;SslMode=None", "ConnectionString": "AllowLoadLocalInfile=true;Server=192.168.2.9;User ID=root;Password=qwe123!@#;Port=3306;Database=learn.videoanalysis;CharSet=utf8mb4;pooling=true;SslMode=None",
"SqlType": "MySql", "SqlType": "MySql",
"UpdateTable": false "UpdateTable": true
}, },
"AlibabaCloudVod": { "AlibabaCloudVod": {
"AccessKeyId": "LTAI5tDC6p9h747B7FHbgwkH", "AccessKeyId": "LTAI5tDC6p9h747B7FHbgwkH",
"AccessKeySecret": "vRKgmbp1LB05LaGOjh3ZrZxbHSLYLF", "AccessKeySecret": "vRKgmbp1LB05LaGOjh3ZrZxbHSLYLF",
"EndPoint": "vod.cn-shanghai.aliyuncs.com" // "EndPoint": "vod.cn-shanghai.aliyuncs.com" //
}, },
"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" //
},
"OtherDBArr": [ "OtherDBArr": [
{ {
"ConfigId": 1001, //ResourceBank "ConfigId": 1001, //ResourceBank

View File

@ -204,13 +204,14 @@ namespace VideoAnalysisCore.AICore.GPT.ChatGPT
messages = messageArr messages = messageArr
}; };
RedisExpand.SetTaskGPTReqCached(task, chatRep); var time = DateTime.Now.ToString("MMddHHmmss");
RedisExpand.SetTaskGPTCached(task, time,chatRep);
var chatResp = await chatClient.Chat(chatRep); var chatResp = await chatClient.Chat(chatRep);
var chatResContent = chatResp?.res; var chatResContent = chatResp?.res;
if (string.IsNullOrEmpty(chatResContent)) if (string.IsNullOrEmpty(chatResContent))
throw new Exception("GPT返回message无效结果"); throw new Exception("GPT返回message无效结果");
if (chatResp != null) if (chatResp != null)
RedisExpand.SetTaskGPTCached(task, new object[] { chatResp.Value.res, chatResp.Value.u }); RedisExpand.SetTaskGPTCached(task, time, new object[] { chatResp.Value.res, chatResp.Value.u });
chatResContent = chatResContent?.Replace("字幕内容", "课堂情况"); chatResContent = chatResContent?.Replace("字幕内容", "课堂情况");
chatResContent = chatResContent?.Replace("\n", ""); chatResContent = chatResContent?.Replace("\n", "");
@ -307,13 +308,14 @@ namespace VideoAnalysisCore.AICore.GPT.ChatGPT
] ]
}; };
RedisExpand.SetTaskGPTReqCached(task, chatRep); var time = DateTime.Now.ToString("MMddHHmmss");
RedisExpand.SetTaskGPTCached(task, time, chatRep);
var chatResp = await chatClient.Chat(chatRep); var chatResp = await chatClient.Chat(chatRep);
var chatResContent = chatResp?.res; var chatResContent = chatResp?.res;
if (string.IsNullOrEmpty(chatResContent)) if (string.IsNullOrEmpty(chatResContent))
throw new Exception("GPT返回message无效结果"); throw new Exception("GPT返回message无效结果");
if (chatResp != null) if (chatResp != null)
RedisExpand.SetTaskGPTCached(task, new object[] { chatResp.Value.res, chatResp.Value.u }); RedisExpand.SetTaskGPTCached(task, time, new object[] { chatResp.Value.res, chatResp.Value.u });
chatResContent = chatResContent?.Replace("字幕内容", "课堂情况"); chatResContent = chatResContent?.Replace("字幕内容", "课堂情况");
chatResContent = chatResContent?.Replace("\n", ""); chatResContent = chatResContent?.Replace("\n", "");

View File

@ -16,6 +16,8 @@ using System.Linq;
using System.Security.Cryptography; using System.Security.Cryptography;
using static System.Collections.Specialized.BitVector32; using static System.Collections.Specialized.BitVector32;
using FFmpeg.NET.Services; using FFmpeg.NET.Services;
using Aliyun.OSS;
using Yitter.IdGenerator;
namespace VideoAnalysisCore.AICore.GPT.DeepSeek namespace VideoAnalysisCore.AICore.GPT.DeepSeek
{ {
@ -29,14 +31,16 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
private readonly Repository<VideoTask> videoTaskDB; private readonly Repository<VideoTask> videoTaskDB;
private readonly Repository<VideoKonwPoint> videoKonwPointDB; private readonly Repository<VideoKonwPoint> videoKonwPointDB;
private readonly Repository<VideoQuestion> videoQuestionDB; private readonly Repository<VideoQuestion> videoQuestionDB;
private readonly Repository<VideoQuestionKonw> videoQuestionKonwDB;
private readonly Repository<KnowledgeInfo> knowledgeInfoDB; private readonly Repository<KnowledgeInfo> knowledgeInfoDB;
private readonly SimpLetexClient simpLetexClient; private readonly SimpLetexClient simpLetexClient;
private readonly OssClient ossClient;
/// <summary> /// <summary>
/// 初始化 /// 初始化
/// </summary> /// </summary>
/// <param name="moonshotClient"></param> /// <param name="moonshotClient"></param>
/// <param name="logger"></param> /// <param name="logger"></param>
public DeepSeek_GPT(DeepSeekGPTClient moonshotClient, Repository<CourseGradingCriteria> criteria, Repository<VideoTask> videoTaskDB, Repository<KnowledgeInfo> knowledgeInfoDB, Repository<VideoKonwPoint> videoKonwPointDB, SimpLetexClient simpLetexClient, Repository<VideoQuestion> videoQuestionDB) public DeepSeek_GPT(DeepSeekGPTClient moonshotClient, Repository<CourseGradingCriteria> criteria, Repository<VideoTask> videoTaskDB, Repository<KnowledgeInfo> knowledgeInfoDB, Repository<VideoKonwPoint> videoKonwPointDB, SimpLetexClient simpLetexClient, Repository<VideoQuestion> videoQuestionDB, OssClient ossClient, Repository<VideoQuestionKonw> videoQuestionKonwDB)
{ {
chatClient = moonshotClient; chatClient = moonshotClient;
criteriaDB = criteria; criteriaDB = criteria;
@ -45,6 +49,8 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
this.videoKonwPointDB = videoKonwPointDB; this.videoKonwPointDB = videoKonwPointDB;
this.simpLetexClient = simpLetexClient; this.simpLetexClient = simpLetexClient;
this.videoQuestionDB = videoQuestionDB; this.videoQuestionDB = videoQuestionDB;
this.ossClient = ossClient;
this.videoQuestionKonwDB = videoQuestionKonwDB;
} }
/// <summary> /// <summary>
/// 获取内容对应的章节 /// 获取内容对应的章节
@ -81,7 +87,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
$" 格式 (方法点Id|方法点名称) " + $" 格式 (方法点Id|方法点名称) " +
$"提供的知识点名称({knows})。"; $"提供的知识点名称({knows})。";
Console.WriteLine(DateTime.Now + "=>2.开始分析视频内容知识点"); Console.WriteLine(DateTime.Now + "=>2.开始分析视频内容知识点");
var konwRes = await ChatAsync<VideoKnowRes[]>(taskInfo.Id.ToString(), knowMessages, null); var konwRes = await ChatAsync<VideoKnowRes[]>(taskInfo.Id.ToString(), knowMessages, "知识点");
for (int i = 0; i < konwRes.Count(); i++) for (int i = 0; i < konwRes.Count(); i++)
questionRes[i].KnowPoint = konwRes[i].KnowPoint; questionRes[i].KnowPoint = konwRes[i].KnowPoint;
@ -95,6 +101,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
s => s =>
{ {
var ks = s.KnowPoint.Split(",").Distinct(); var ks = s.KnowPoint.Split(",").Distinct();
var StageId=Yitter.IdGenerator.YitIdHelper.NextId();
return ks.Where(x => knowDic.ContainsKey(x)) return ks.Where(x => knowDic.ContainsKey(x))
.Select(x => new VideoKonwPoint() .Select(x => new VideoKonwPoint()
{ {
@ -102,6 +109,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
Theme = s.Theme, Theme = s.Theme,
StartTime = s.StartTime, StartTime = s.StartTime,
EndTime = s.EndTime, EndTime = s.EndTime,
StageId = StageId,
KnowPoint = x, KnowPoint = x,
KnowPointId = knowDic[x].ToString(), KnowPointId = knowDic[x].ToString(),
TagId = taskInfo.TagId, TagId = taskInfo.TagId,
@ -144,7 +152,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
$"输出格式 json字符串 对象格式{fileNameResFormat}"; $"输出格式 json字符串 对象格式{fileNameResFormat}";
var task = taskInfo.Id.ToString(); var task = taskInfo.Id.ToString();
var fileNameInfoRes = await ChatAsync<FileNameInfo> var fileNameInfoRes = await ChatAsync<FileNameInfo>
(task, fileNamePostMessages, null); (task, fileNamePostMessages, "授课章节");
taskInfo.Sections = fileNameInfoRes.; taskInfo.Sections = fileNameInfoRes.;
await videoTaskDB.AsUpdateable() await videoTaskDB.AsUpdateable()
.SetColumns(it => it.Sections == fileNameInfoRes.) .SetColumns(it => it.Sections == fileNameInfoRes.)
@ -174,7 +182,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
$"字幕格式(说话人:开始秒:结束秒:内容|下一段字幕).以下是包含时间的视频字幕文本。字幕列表 {captions.Captions}。" + $"字幕格式(说话人:开始秒:结束秒:内容|下一段字幕).以下是包含时间的视频字幕文本。字幕列表 {captions.Captions}。" +
$"最后输出格式为json({checkResFormat})"; $"最后输出格式为json({checkResFormat})";
Console.WriteLine(DateTime.Now + "=>3.开始检查视频分段结果"); Console.WriteLine(DateTime.Now + "=>3.开始检查视频分段结果");
return await ChatAsync<CheckMessageDto>(taskInfo.Id.ToString(), checkMessage, null); return await ChatAsync<CheckMessageDto>(taskInfo.Id.ToString(), checkMessage, "结果检查");
} }
/// <summary> /// <summary>
@ -202,20 +210,20 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
.Take(spanCount); .Take(spanCount);
if (cArr.Count() == 0) if (cArr.Count() == 0)
return; return;
var nowCaptionStr = string.Join('|', cArr.Select(s => /*s.Start + ":" +*/ s.Text)); var nowCaptionStr =JsonSerializer.Serialize(cArr.Select(s =>s.Text));
var resFormat = """[string(修改结果)]"""; var resFormat = """[string(修改结果)]""";
var postMessages = var postMessages =
$"这是一堂中国课的字幕由结果是语音识别提供。" + $"这是一堂中国课的字幕由结果是语音识别提供。" +
$"字幕内容与{subject}学科{sections}章节相关。" + $"字幕内容与{subject}学科{sections}章节相关。" +
$"需要你帮我修复其中的错别字,修复公式。" + $"需要你帮我修复其中的错别字,修复公式。" +
$"请注意 只允许对字幕进行修改不允许删除字幕的字或者添加字。" + $"请注意 只允许对字幕进行修改不允许删除字幕的字或者添加字。" +
$"请确保输出字幕条数与输入字幕条数一致!!!" +
$"输出内容只返回json格式({resFormat})" + $"输出内容只返回json格式({resFormat})" +
$"字幕内容(使用|符号分割)" + $"字幕内容(JSON字符串)" +
$"`{nowCaptionStr}`" + $"`{nowCaptionStr}`" +
$"字幕结束。 "; $"字幕结束。" +
$"最后请确保输出字幕条数与输入字幕条数一致!!! 如果不一致则重新优化并且确保字幕条数一致!!!!";
Console.WriteLine(DateTime.Now + $"=>字幕优化 分段{s}/{totalCount}开始..."); Console.WriteLine(DateTime.Now + $"=>字幕优化 分段{s}/{totalCount}开始...");
var resData = await ChatAsync<string[]>(taskInfo.Id.ToString(), postMessages, null, "deepseek-chat"); var resData = await ChatAsync<string[]>(taskInfo.Id.ToString(), postMessages, "优化字幕", "deepseek-chat");
if (resData.Count() != cArr.Count()) if (resData.Count() != cArr.Count())
{ {
Console.WriteLine(DateTime.Now + $"=>字幕优化 分段{s}/{totalCount} AI结果数量不匹配,重试"); Console.WriteLine(DateTime.Now + $"=>字幕优化 分段{s}/{totalCount} AI结果数量不匹配,重试");
@ -280,7 +288,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
$"字幕列表 {nowCaptionStr} 字幕结束!"; $"字幕列表 {nowCaptionStr} 字幕结束!";
Console.WriteLine(DateTime.Now + $"=>{taskInfo.Id.ToString()}.开始分析视频内容 {lastTime}~{endTime}"); Console.WriteLine(DateTime.Now + $"=>{taskInfo.Id.ToString()}.开始分析视频内容 {lastTime}~{endTime}");
questionRes.AddRange(await ChatAsync<VideoKnowRes[]>(taskInfo.Id.ToString(), postMessages, null)); questionRes.AddRange(await ChatAsync<VideoKnowRes[]>(taskInfo.Id.ToString(), postMessages, "分析字幕"));
lastTime = (int)questionRes.Last().EndTime.Value - (lastTime == 0 ? 0 : 30); lastTime = (int)questionRes.Last().EndTime.Value - (lastTime == 0 ? 0 : 30);
} }
catch (Exception ex) catch (Exception ex)
@ -317,8 +325,8 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
Course_Id = 27; Course_Id = 27;
break; break;
} }
if(taskInfo.VideoType == AttachmentsInfoType.Review)
//AnalysisVideoQuestions(taskInfo,) await AnalysisVideoQuestions(taskInfo);
var captionsArr = JsonSerializer.Deserialize<SenseVoiceRes[]>(taskInfo.Captions); var captionsArr = JsonSerializer.Deserialize<SenseVoiceRes[]>(taskInfo.Captions);
@ -371,11 +379,10 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
return null; return null;
} }
public async Task<T> ChatAsync<T>(string task, string postMessages, string postMessages1, string model = "deepseek-reasoner") public async Task<T> ChatAsync<T>(string task, string postMessages, string title, string model = "deepseek-reasoner")
{ {
Message[] messageArr = [ Message[] messageArr = [
new Message(postMessages,"user"), new Message(postMessages,"user"),
string.IsNullOrEmpty(postMessages1)?null:new Message(postMessages1,"user"),
]; ];
messageArr = messageArr.Where(s => s != null).ToArray(); messageArr = messageArr.Where(s => s != null).ToArray();
var chatRep = new ChatRequest var chatRep = new ChatRequest
@ -391,14 +398,17 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
{ {
try try
{ {
RedisExpand.SetTaskGPTReqCached(task, chatRep); var time = title+DateTime.Now.ToString("MMddHHmmss");
var redisCached = new object[2] { chatRep, null };
RedisExpand.SetTaskGPTCached(task, time,chatRep);
var chatResp = await chatClient.Chat(chatRep); var chatResp = await chatClient.Chat(chatRep);
var chatResContent = chatResp?.res; var chatResContent = chatResp?.res;
if (string.IsNullOrEmpty(chatResContent)) if (string.IsNullOrEmpty(chatResContent))
throw new Exception("GPT返回message无效结果"); throw new Exception("GPT返回message无效结果");
if (chatResp != null) if (chatResp != null) {
RedisExpand.SetTaskGPTCached(task, new object[] { chatResp.Value.res, chatResp.Value.u, chatResp.Value.reasoning }); redisCached[1] = new object[] { chatResp.Value.res, chatResp.Value.u, chatResp.Value.reasoning };
RedisExpand.SetTaskGPTCached(task, time, redisCached);
}
chatResContent = chatResContent?.Replace("字幕内容", "课堂情况"); chatResContent = chatResContent?.Replace("字幕内容", "课堂情况");
chatResContent = chatResContent?.Replace("\n", ""); chatResContent = chatResContent?.Replace("\n", "");
chatResContent = chatResContent?.Replace("```json", ""); chatResContent = chatResContent?.Replace("```json", "");
@ -437,17 +447,18 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
/// <summary> /// <summary>
/// 优化字幕 /// 提取试题
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
private async Task<SenseVoiceRes[]> AnalysisVideoQuestions(VideoTask taskInfo) private async Task<SenseVoiceRes[]> AnalysisVideoQuestions(VideoTask taskInfo)
{ {
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 videoKnowArr = await videoKonwPointDB.GetListAsync(s => s.VideoTaskId == taskInfo.Id); var videoKnowArr = await videoKonwPointDB.GetListAsync(s => s.VideoTaskId == taskInfo.Id);
var insertData =new List<VideoQuestion>(); var insertData =new List<VideoQuestionOSSDto>();
var insertQuestionKonw = new List<VideoQuestionKonw>();
foreach (var item in farmeArr) foreach (var item in farmeArr)
{ {
var knowInfoArr = videoKnowArr var knowInfoArr = videoKnowArr
@ -455,33 +466,47 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
.ToArray(); .ToArray();
if (knowInfoArr is null || knowInfoArr.Count() ==0) if (knowInfoArr is null || knowInfoArr.Count() ==0)
return null; return null;
while (true) var tryCount = 50;
while (tryCount>1)
{ {
tryCount--;
try try
{ {
var filePath = taskInfo.FramePath(item);
var sRes = await simpLetexClient var sRes = await simpLetexClient
.ProcessImageAsync(new SimpleTexOcrRequest(taskInfo.FramePath(item))); .ProcessImageAsync(new SimpleTexOcrRequest(filePath));
if (!sRes.Success) if (!sRes.Success)
continue; continue;
var knowArr=string.Join(',', knowInfoArr.Select(s => s.KnowPoint + "|"+s.KnowPointId)); var knowArr=string.Join(',', knowInfoArr.Select(s => s.KnowPoint + "|"+s.KnowPointId));
var resFormat = """[{"TopicStem":string(试题题干),"Question:string()","KnowPointId":(string)知识点ID(多个使用逗号拼接)}]"""; var resFormat = """[{"TopicStem":string(试题题干),"Question:string()","KnowPointId":(string)知识点ID}]""";
var postMessages = var postMessages =
$"提供一段内容是md格式的试题内容字符串。" + $"提供一段内容是md格式的试题内容字符串。" +
$"请提取出其中的试题内容。并且为他们关联上在我限定范围内的知识点。" + $"请提取出其中的试题内容。并且为每个试题关联上在我限定范围内的知识点(多个则用逗号分割)。" +
$"知识点范围[{knowArr}]。" + $"知识点范围[{knowArr}]。" +
$"排除不是试题内容的文字,优化公式排版并且去除题号。" + $"排除不是试题内容的文字,优化公式排版并且去除题号。" +
$"如果存在多道大题,请帮忙拆分开!" + $"如果存在多道大题,请帮忙拆分开!" +
$"输出内容只返回json格式为({resFormat})" + $"输出内容只返回json格式为({resFormat})" +
$"以下是试题内容" + $"以下是试题内容" +
$"`{sRes.Result.res.info.markdown}`"; $"`{sRes.Result.res.info.markdown}`";
var resData = await ChatAsync<VideoQuestion[]>(taskInfo.Id.ToString(), postMessages, null, "deepseek-chat"); var resData = await ChatAsync<VideoQuestionOSSDto[]>(taskInfo.Id.ToString(), postMessages, "提取试题", "deepseek-chat");
foreach (var q in resData) foreach (var q in resData)
{ {
q.FilePath = filePath;
q.VideoTaskId = taskInfo.Id; q.VideoTaskId = taskInfo.Id;
q.VideoKonwPoint = knowInfoArr.First().Id; q.StageId = knowInfoArr.First().StageId;
foreach (var kid in q.KnowPointId.Split(","))
{
insertQuestionKonw.Add(new VideoQuestionKonw()
{
KnowPoint = knowInfoArr.First(s => s.KnowPointId == kid).KnowPoint,
KnowPointId= kid,
StageId =q.StageId,
VideoTaskId = q.VideoTaskId,
});
}
} }
//处理知识点
insertData.AddRange(resData); insertData.AddRange(resData);
break;
} }
catch (Exception) catch (Exception)
{ {
@ -489,9 +514,17 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
} }
} }
} }
//分组共同题干试题ID
foreach (var item in insertData.GroupBy(x => x.TopicStem))
await videoQuestionDB.InsertRangeAsync(insertData); {
var keyId=YitIdHelper.NextId();
foreach (var s in item)
s.TopicId = keyId;
}
//上传oss
ossClient.AddVideoQuestionUrl(insertData);
await videoQuestionDB.InsertRangeAsync(insertData.Adapt<VideoQuestion[]>());
await videoQuestionKonwDB.InsertRangeAsync(insertQuestionKonw);
return null; return null;
} }

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,57 @@
{
"Env": [],
"IIsConfig": {
"SdkType": null,
"WebSiteName": "",
"LastEnvName": null,
"EnvPairList": []
},
"WindowsServiveConfig": {
"ServiceName": "",
"SdkType": null,
"LastEnvName": null,
"EnvPairList": []
},
"LinuxServiveConfig": {
"ServiceName": "",
"EnvParam": "",
"LastEnvName": null,
"EnvPairList": []
},
"DockerConfig": {
"Prot": "",
"AspNetCoreEnv": "",
"LastEnvName": null,
"RemoveDaysFromPublished": "10",
"WorkDir": "",
"Volume": "",
"Other": "",
"EnvPairList": []
},
"DockerImageConfig": {
"BaseHttpProxy": "",
"BaseImage": "",
"BaseImageCredential": {
"UserName": "",
"Password": ""
},
"TargetImage": "",
"TargetHttpProxy": "",
"TargetTags": [
""
],
"TargetImageCredential": {
"UserName": "",
"Password": ""
},
"ImageFormat": "Docker",
"Entrypoint": [
""
],
"Cmd": [
""
],
"IgnoreList": [],
"SkipExistingImages": false
}
}

View File

@ -99,7 +99,7 @@ namespace VideoAnalysisCore.Common
/// <returns></returns> /// <returns></returns>
public static string FramePath(this VideoTask task, int fTime) public static string FramePath(this VideoTask task, int fTime)
{ {
return Path.Combine(task.Id.ToString().LocalPath(), $"{FrameName}{fTime / 5}.jpg"); return Path.Combine(task.Id.ToString().LocalPath(), $"{FrameName}{(fTime / 5).ToString().PadLeft(3,'0')}.jpg");
} }
/// <summary> /// <summary>

View File

@ -44,6 +44,7 @@ namespace VideoAnalysisCore.Common
/// 阿里云视频点播配置 /// 阿里云视频点播配置
/// </summary> /// </summary>
public AlibabaCloudVodConfig AlibabaCloudVod { get; set; } = new AlibabaCloudVodConfig(); public AlibabaCloudVodConfig AlibabaCloudVod { get; set; } = new AlibabaCloudVodConfig();
public AliyunOSSConfig AliyunOSS { get; set; } = new AliyunOSSConfig();
/// <summary> /// <summary>

View File

@ -0,0 +1,113 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using AlibabaCloud.OpenApiClient.Models;
using AlibabaCloud.SDK.Vod20170321;
using AlibabaCloud.SDK.Vod20170321.Models;
using AlibabaCloud.TeaUtil.Models;
using Aliyun.OSS.Common;
using Aliyun.OSS;
using Microsoft.Extensions.DependencyInjection;
using VideoAnalysisCore.Job;
using VideoAnalysisCore.Model;
using System.Security.AccessControl;
using Aliyun.Credentials.Models;
using VideoAnalysisCore.Model.Dto;
using System.IO;
namespace VideoAnalysisCore.Common
{
public class AliyunOSSConfig
{
/// <summary>
/// id
/// </summary>
public string AccessKeyId { get; set; }
/// <summary>
///密钥
/// </summary>
public string AccessKeySecret { get; set; }
/// <summary>
/// 区域Url
/// </summary>
public string Region { get; set; }
/// <summary>
/// 筒域名
/// </summary>
public string BucketDomain { get; set; }
/// <summary>
/// 桶名称
/// </summary>
public string BucketName { get; set; }
public string Endpoint { get; set; } = "oss-cn-chengdu.aliyuncs.com";
}
/// <summary>
/// 阿里云 视频点播拓展
/// </summary>
public static class AliyunOSSExpand
{
/// <summary>
/// 使用阿里云 vod拓展
/// </summary>
/// <param name="service"></param>
/// <returns></returns>
public static void AddAliyunOSS(this IServiceCollection service)
{
Console.WriteLine($"{DateTime.Now}=>初始化 阿里云OSS");
AliyunOSSConfig config = new()
{
// 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID。
AccessKeyId = AppCommon.Config.AliyunOSS.AccessKeyId,
// 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_SECRET。
AccessKeySecret = AppCommon.Config.AliyunOSS.AccessKeySecret,
Endpoint = AppCommon.Config.AliyunOSS.Endpoint
};// 创建ClientConfiguration实例按照您的需要修改默认参数。
var conf = new ClientConfiguration();
// 设置v4签名。
conf.SignatureVersion = SignatureVersion.V4;
// 创建OssClient实例。
var oss = new OssClient(config.Endpoint, config.AccessKeyId, config.AccessKeySecret, conf);
oss.SetRegion(config.Region);
service.AddSingleton(oss);
}
/// <summary>
/// 上传文件
/// </summary>
/// <param name="oss"></param>
/// <param name="fileArr">视频尸体片段</param>
public static void AddVideoQuestionUrl(this OssClient oss, List<VideoQuestionOSSDto> fileArr )
{
var cached = new HashSet<string>();
foreach (var item in fileArr)
{
try
{
var path = item.VideoTaskId.ToString() + "/" + Path.GetFileName(item.FilePath);
if (cached.Contains(item.FilePath))
{
item.ImageUrl = AppCommon.Config.AliyunOSS.BucketDomain + "/" + path;
continue;
}
using var file = File.OpenRead(item.FilePath);
var result = oss
.PutObject(
AppCommon.Config.AliyunOSS.BucketName,
path,
file);
item.ImageUrl = AppCommon.Config.AliyunOSS.BucketDomain + "/" + path;
cached.Add(item.FilePath);
continue;
}
catch (Exception)
{
}
}
}
}
}

View File

@ -58,7 +58,7 @@ namespace VideoAnalysisCore.Common
/// 用以指定识别图片的类型如果使用auto则会自动检测使用document会返回markdown文档结果使用formula会返回LaTeX结果 /// 用以指定识别图片的类型如果使用auto则会自动检测使用document会返回markdown文档结果使用formula会返回LaTeX结果
/// <para>"auto", "document", "formula"</para> /// <para>"auto", "document", "formula"</para>
/// </summary> /// </summary>
public string rec_mode { get; set; } = "auto"; public string rec_mode { get; set; } = "document";
/// <summary> /// <summary>
/// 开启后模型将基于0°90°, 180°, 270°自动矫正上传图片的方向默认不开启 /// 开启后模型将基于0°90°, 180°, 270°自动矫正上传图片的方向默认不开启
/// </summary> /// </summary>
@ -159,8 +159,9 @@ namespace VideoAnalysisCore.Common
try try
{ {
var response = await client.SendAsync(requestMessage); var response = await client.SendAsync(requestMessage);
var resStr = await response.Content.ReadAsStringAsync();
var responseContent = await response.Content.ReadFromJsonAsync<SimpleTexOcrResponseData>(); var responseContent = await response.Content.ReadFromJsonAsync<SimpleTexOcrResponseData>();
request.file.Dispose();
return new SimpleTexOcrResponse return new SimpleTexOcrResponse
{ {
Success = response.IsSuccessStatusCode, Success = response.IsSuccessStatusCode,

View File

@ -1,15 +0,0 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VideoAnalysisCore.Common.Expand
{
public static class StartUpExpand
{
}
}

View File

@ -106,13 +106,9 @@ namespace VideoAnalysisCore.Common
/// 缓存GPT任务缓存 /// 缓存GPT任务缓存
/// </summary> /// </summary>
/// <param name="taskId"></param> /// <param name="taskId"></param>
public static void SetTaskGPTCached(object taskId, object? data) public static void SetTaskGPTCached(object taskId,string time, object? data)
{ {
Redis.Set(RedisExpandKey.TaskGPT(taskId) + ":" + DateTime.Now.ToString("MMddHHmmss") + "01", data, 3600 * 24); Redis.Set(RedisExpandKey.TaskGPT(taskId) + ":" + time, data, 3600 * 24);
}
public static void SetTaskGPTReqCached(object taskId, object? data)
{
Redis.Set(RedisExpandKey.TaskGPT(taskId) + ":" + DateTime.Now.ToString("MMddHHmmss")+ "00", data, 3600 * 24);
} }
/// <summary> /// <summary>
/// 加入到消费队列 /// 加入到消费队列

View File

@ -168,6 +168,7 @@ namespace VideoAnalysisCore.Controllers
TagId = req.TagId, TagId = req.TagId,
MediaName = req.Name, MediaName = req.Name,
PPTVideoCode = req.PPTVideoCode, PPTVideoCode = req.PPTVideoCode,
VideoType=req.VideoType
}; };
//Èë¿â //Èë¿â
var hashEntries = task.GetType() var hashEntries = task.GetType()

View File

@ -121,6 +121,10 @@ namespace VideoAnalysisCore.Controllers.Dto
/// </summary> /// </summary>
public TaskTypeEnum? Type { get; set; } public TaskTypeEnum? Type { get; set; }
/// <summary> /// <summary>
/// 视频类型
/// </summary>
public AttachmentsInfoType? VideoType { get; set; }
/// <summary>
/// 自定义值 任务完成后附带通知 /// 自定义值 任务完成后附带通知
/// </summary> /// </summary>
public string Tag { get; set; } = string.Empty; public string Tag { get; set; } = string.Empty;

View File

@ -95,7 +95,7 @@ namespace VideoAnalysisCore.Controllers
TaskType = req.TaskType, TaskType = req.TaskType,
SubjectType = req.SubjectType, SubjectType = req.SubjectType,
VideoUrl =s.VideoUrl, VideoUrl =s.VideoUrl,
CallBackUrl=s.CallBackUrl CallBackUrl=s.CallBackUrl,
}; };
nodePackages.Add(np); nodePackages.Add(np);
if (s.AttachmentsInfoType == AttachmentsInfoType.PPT) if (s.AttachmentsInfoType == AttachmentsInfoType.PPT)
@ -117,6 +117,7 @@ namespace VideoAnalysisCore.Controllers
MediaUrl =s.VideoUrl, MediaUrl =s.VideoUrl,
MediaName = s.VideoName, MediaName = s.VideoName,
PPTVideoCode = pptCode, PPTVideoCode = pptCode,
VideoType =s.AttachmentsInfoType
}); });
} }
await nodePackageInfoDB.InsertRangeAsync(nodePackages); await nodePackageInfoDB.InsertRangeAsync(nodePackages);

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VideoAnalysisCore.Model.Dto
{
public class VideoQuestionOSSDto: VideoQuestion
{
public string FilePath { get; set; }
public string KnowPointId { get; set; }
}
}

View File

@ -20,13 +20,17 @@ namespace VideoAnalysisCore.Model
/// <summary> /// <summary>
/// id /// id
/// </summary> /// </summary>
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)] [SugarColumn(IsPrimaryKey = true)]
public long Id { get; set; } public long Id { get; set; }
/// <summary> /// <summary>
/// 视频任务id /// 视频任务id
/// </summary> /// </summary>
public long VideoTaskId { get; set; } public long VideoTaskId { get; set; }
/// <summary> /// <summary>
/// 视频阶段id
/// </summary>
public long StageId { get; set; }
/// <summary>
/// 自定义Id [任务视频自定义id] /// 自定义Id [任务视频自定义id]
/// <see cref="VideoTask.TagId"/> /// <see cref="VideoTask.TagId"/>
/// </summary> /// </summary>
@ -67,6 +71,7 @@ namespace VideoAnalysisCore.Model
/// <summary> /// <summary>
/// 课程阶段 /// 课程阶段
/// </summary> /// </summary>
[SugarColumn(IsIgnore = true)]
public virtual StageEnum? Stage { get; set; } public virtual StageEnum? Stage { get; set; }
} }
} }

View File

@ -27,22 +27,26 @@ namespace VideoAnalysisCore.Model
/// </summary> /// </summary>
public long VideoTaskId { get; set; } public long VideoTaskId { get; set; }
/// <summary> /// <summary>
/// 视频片段ID /// 视频阶段id
/// <para>隶属于<see cref="VideoKonwPoint.Id"/></para> /// <para>隶属于<see cref="VideoKonwPoint.StageId"/></para>
/// </summary> /// </summary>
public long VideoKonwPoint { get; set; } public long StageId { get; set; }
/// <summary> /// <summary>
/// 知识点 /// 题干id
/// <para>[用于多个一个题干多个问题]</para>
/// </summary> /// </summary>
public string? KnowPoint { get; set; } public long TopicId { get; set; }
/// <summary> /// <summary>
/// 知识点ID /// 图片地址
/// </summary> /// </summary>
public string? KnowPointId { get; set; } [SugarColumn(Length =100)]
public string? ImageUrl { get; set; }
/// <summary> /// <summary>
/// 题干 /// 题干
/// </summary> /// </summary>
[SugarColumn(ColumnDataType ="text")]
public string? TopicStem { get; set; } public string? TopicStem { get; set; }
/// <summary> /// <summary>
/// 问题(设问) /// 问题(设问)

View File

@ -0,0 +1,43 @@
using SqlSugar;
using System.ComponentModel.DataAnnotations;
using System.Net;
using System.Text.Json;
using UserCenter.Model.Enum;
using VideoAnalysisCore.AICore.GPT.Dto;
using VideoAnalysisCore.AICore.SherpaOnnx;
using VideoAnalysisCore.Model.Enum;
using VideoAnalysisCore.Model.Interface;
using Whisper.net;
namespace VideoAnalysisCore.Model
{
/// <summary>
/// 视频片段试题知识点关系表
/// </summary>
[SugarTable("videoquestionkonw")]
public class VideoQuestionKonw : IDB
{
/// <summary>
/// id
/// </summary>
[SugarColumn(IsPrimaryKey = true)]
public long Id { get; set; }
/// <summary>
/// 视频任务id
/// </summary>
public long VideoTaskId { get; set; }
/// <summary>
/// 知识点名称
/// </summary>
public string KnowPoint { get; set; }
/// <summary>
/// 知识点ID
/// </summary>
public string KnowPointId { get; set; }
/// <summary>
/// 视频阶段id
/// <para>隶属于<see cref="VideoKonwPoint.StageId"/></para>
/// </summary>
public long StageId { get; set; }
}
}

View File

@ -59,6 +59,12 @@ namespace VideoAnalysisCore.Model
[SugarColumn(IsNullable = true)] [SugarColumn(IsNullable = true)]
public TaskTypeEnum? Type { get; set; } public TaskTypeEnum? Type { get; set; }
/// <summary> /// <summary>
/// 视频类型
/// <para>常规,教研,PPT...</para>
/// </summary>
[SugarColumn(IsNullable = true)]
public AttachmentsInfoType? VideoType { get; set; }
/// <summary>
/// 自定义值 任务完成后附带通知 /// 自定义值 任务完成后附带通知
/// </summary> /// </summary>
[SugarColumn(Length = 500, IsNullable = true)] [SugarColumn(Length = 500, IsNullable = true)]

View File

@ -59,6 +59,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="AlibabaCloud.SDK.Vod20170321" Version="3.6.1" /> <PackageReference Include="AlibabaCloud.SDK.Vod20170321" Version="3.6.1" />
<PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.14.1" />
<PackageReference Include="Coravel" Version="6.0.2" /> <PackageReference Include="Coravel" Version="6.0.2" />
<PackageReference Include="FreeRedis" Version="1.3.2" /> <PackageReference Include="FreeRedis" Version="1.3.2" />
<PackageReference Include="Downloader" Version="3.2.1" /> <PackageReference Include="Downloader" Version="3.2.1" />