From 0edf143f8a552983f975628e383dbc303866c83f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E8=82=A5=E7=BE=8A?= <1048382248@qq.com> Date: Mon, 29 Sep 2025 17:32:08 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=20=E5=90=84=E4=B8=AA?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=E7=9A=84=E6=B3=A8=E5=85=A5=E6=96=B9=E5=BC=8F?= =?UTF-8?q?=20=E4=BF=AE=E5=A4=8D=20=E5=88=9D=E5=A7=8B=E5=8C=96=E6=97=B6=20?= =?UTF-8?q?=E4=B9=8B=E5=89=8D=E6=9C=AA=E6=89=A7=E8=A1=8C=E5=AE=8C=E7=9A=84?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=20=E5=AF=BC=E8=87=B4=E7=9A=84=E6=AD=BB?= =?UTF-8?q?=E5=BE=AA=E7=8E=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Learn.VideoAnalysis.API/Program.cs | 6 + .../Components/Pages/VideoTaskPage.razor.cs | 10 +- .../Components/Pages/VideoTaskShow.razor.cs | 3 +- VideoAnalysis/Program.cs | 10 +- .../AICore/FFMPGE/FFMPGEHandle.cs | 45 ++-- .../AICore/GPT/ChatGPT/Chat_GPT.cs | 18 +- .../AICore/GPT/DeepSeek/DeepSeekClient.cs | 7 +- .../AICore/GPT/DeepSeek/DeepSeek_GPT.cs | 15 +- .../AICore/SherpaOnnx/SenseVoice.cs | 70 ++++-- .../AICore/SherpaOnnx/Speaker.cs | 14 +- .../AICore/Whisper/WhisperHandle.cs | 2 +- VideoAnalysisCore/Common/DownloadFile.cs | 8 +- .../Common/Expand/SqlSugarExpand.cs | 2 +- VideoAnalysisCore/Common/RedisExpand.cs | 215 +++++++++++------- VideoAnalysisCore/Common/Repository.cs | 8 +- .../Controllers/ApiController.cs | 18 +- .../Controllers/LJZK_Controller.cs | 6 +- VideoAnalysisCore/Job/NodeSubscriptionJob.cs | 132 +++++------ 18 files changed, 350 insertions(+), 239 deletions(-) diff --git a/Learn.VideoAnalysis.API/Program.cs b/Learn.VideoAnalysis.API/Program.cs index d692850..7914399 100644 --- a/Learn.VideoAnalysis.API/Program.cs +++ b/Learn.VideoAnalysis.API/Program.cs @@ -2,7 +2,9 @@ using Learn.VideoAnalysis.API.Expand; using Mapster; using Microsoft.OpenApi.Models; +using VideoAnalysisCore.AICore.FFMPGE; using VideoAnalysisCore.AICore.GPT.DeepSeek; +using VideoAnalysisCore.AICore.SherpaOnnx; using VideoAnalysisCore.Common; using VideoAnalysisCore.Common.Expand; @@ -37,8 +39,12 @@ namespace Learn.VideoAnalysis.API builder.Services.AddHttpClient(); builder.Services.AddSqlSugarExpand(); builder.Services.AddRedisExpand(); + builder.Services.AddCoravel(); builder.Services.AddCorsExpand(); + builder.Services.AddDownloadFileExpand(); + builder.Services.AddFFMPGEExpand(); + builder.Services.AddSenseVoiceExpand(); builder.Services.AddHttpContextAccessor(); builder.Services.AddControllersWithViews(options => { diff --git a/VideoAnalysis/Components/Pages/VideoTaskPage.razor.cs b/VideoAnalysis/Components/Pages/VideoTaskPage.razor.cs index e5f3890..ef2fd6f 100644 --- a/VideoAnalysis/Components/Pages/VideoTaskPage.razor.cs +++ b/VideoAnalysis/Components/Pages/VideoTaskPage.razor.cs @@ -23,6 +23,8 @@ namespace Learn.VideoAnalysis.Components.Pages [Inject] private ConfirmService ComfirmService { get; set; } = default!; [Inject] private Repository taskDB { get; set; } = default!; [Inject] private NavigationManager NavigationManager { get; set; } = default!; + [Inject] private RedisManager redisManager { get; set; } = default!; + [Inject] private INotificationService _notice { get; set; } = default!; @@ -54,7 +56,7 @@ namespace Learn.VideoAnalysis.Components.Pages async void ReStartClick(VideoTaskDto query) { selectDefaultValue = - (await RedisExpand.Redis.HMGetAsync(RedisExpandKey.Task(query.Id), "LastEnum")).FirstOrDefault(); + (await redisManager.Redis.HMGetAsync(RedisExpandKey.Task(query.Id), "LastEnum")).FirstOrDefault(); selectEnum = selectDefaultValue; reStartTask = query; modalShow = true; @@ -69,9 +71,9 @@ namespace Learn.VideoAnalysis.Components.Pages /// async void ReStart() { - await RedisExpand.ClearTaskError(reStartTask.Id); + await redisManager.ClearTaskError(reStartTask.Id); _=Task.Run(() => - RedisExpand.InsertChannel((RedisChannelEnum)selectEnum, reStartTask.Id) + redisManager.InsertChannel((RedisChannelEnum)selectEnum, reStartTask.Id) ); modalShow = false; } @@ -125,7 +127,7 @@ namespace Learn.VideoAnalysis.Components.Pages var item = rowData.Data; if (item is null) return; - var data = RedisExpand.Redis.HMGet(RedisExpandKey.Task(item.Id), + var data = redisManager.Redis.HMGet(RedisExpandKey.Task(item.Id), "Progress", "LastEnum", "StartTime", "ErrorMessage"); item.Progress = data[0]; item.LastEnum = data[1] == null ?default:data[1].ToEnum() ?? default; diff --git a/VideoAnalysis/Components/Pages/VideoTaskShow.razor.cs b/VideoAnalysis/Components/Pages/VideoTaskShow.razor.cs index 164728c..9695a7e 100644 --- a/VideoAnalysis/Components/Pages/VideoTaskShow.razor.cs +++ b/VideoAnalysis/Components/Pages/VideoTaskShow.razor.cs @@ -32,6 +32,7 @@ namespace Learn.VideoAnalysis.Components.Pages [Inject] private Repository videoQuestionDB { get; set; } = default!; [Inject] private Repository videoQuestionKonwDB { get; set; } = default!; [Inject] private Repository videoKonwPointDB { get; set; } = default!; + [Inject] private RedisManager redisManager { get; set; } = default!; [Inject] private IJSRuntime JSRuntime { get; set; } = default!; private VideoTask nowTask { get; set; } = default!; @@ -76,7 +77,7 @@ namespace Learn.VideoAnalysis.Components.Pages return; var captionsArr = JsonSerializer.Deserialize(nowTask.Captions); var captionsArr1 = JsonSerializer.Deserialize(nowTask.CaptionsAI??"[]") ; - RedisExpand.Redis.HMGet(RedisExpandKey.Task(taskId), "Captions").FirstOrDefault(); + redisManager.Redis.HMGet(RedisExpandKey.Task(taskId), "Captions").FirstOrDefault(); var konwArr = await videoKonwPointDB.AsQueryable() .Where(s => s.VideoTaskId == nowTask.Id) diff --git a/VideoAnalysis/Program.cs b/VideoAnalysis/Program.cs index c2d7d42..35b5d24 100644 --- a/VideoAnalysis/Program.cs +++ b/VideoAnalysis/Program.cs @@ -68,13 +68,17 @@ namespace Learn.VideoAnalysis builder.Configuration.AddAppConfig(args); builder.Services.AddSqlSugarExpand(); + builder.Services.AddRedisExpand(); + builder.Services.AddSimpleTexOcrClient(); builder.Services.AddDownloadFileExpand(); + builder.Services.AddFFMPGEExpand(); builder.Services.AddAlibabaCloudVod(); builder.Services.AddAliyunOSS(); - builder.Services.AddRedisExpand(); - builder.Services.AddSpeakerAI(); + builder.Services.AddSenseVoiceExpand(); + //builder.Services.AddSpeakerAI(); builder.Services.AddCoravel(); + //SenseVoice.Init(); //쳣 builder.Services.AddControllersWithViews(options => @@ -110,6 +114,7 @@ namespace Learn.VideoAnalysis //builder.Services.AddSingleton(); builder.Services.AddSingleton(); + builder.Services.AddTaskSubscribe(); var app = builder.Build(); @@ -119,6 +124,7 @@ namespace Learn.VideoAnalysis // Configure the HTTP request pipeline. + _ = app.Services.GetRequiredService(); app.UseSwagger(); app.UseSwaggerUI(); app.UseExceptionHandler("/Error"); diff --git a/VideoAnalysisCore/AICore/FFMPGE/FFMPGEHandle.cs b/VideoAnalysisCore/AICore/FFMPGE/FFMPGEHandle.cs index a69ba46..e28afbe 100644 --- a/VideoAnalysisCore/AICore/FFMPGE/FFMPGEHandle.cs +++ b/VideoAnalysisCore/AICore/FFMPGE/FFMPGEHandle.cs @@ -14,9 +14,22 @@ using SixLabors.ImageSharp.Processing; using System.Text.Json; using System; using Microsoft.VisualBasic.FileIO; +using Microsoft.Extensions.DependencyInjection; namespace VideoAnalysisCore.AICore.FFMPGE { + + public static class FFMPGEExpand + { + /// + /// 添加跨域拓展 + /// + /// + public static void AddFFMPGEExpand(this IServiceCollection services) + { + services.AddSingleton(); + } + } /// /// Ffmpeg处理程序 /// @@ -28,21 +41,27 @@ namespace VideoAnalysisCore.AICore.FFMPGE public static string FFmpegPath = RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? $"/usr/bin/ffmpeg" : Path.Combine(AppCommon.AIModelFile, "ffmpeg.exe"); + private Repository videoTaskDB { get; set; } + private RedisManager redisManager { get; set; } + public FFMPGEHandle(RedisManager redisManager, Repository videoTaskDB) + { + this.redisManager = redisManager; + this.videoTaskDB = videoTaskDB; + } /// /// 识别视频关键帧 /// /// 任务id /// - public static async Task VideoKeyFrames(string task) + public async Task VideoKeyFrames(string task) { var taskID = long.Parse(task); //间隔秒 var intervalSec = 5; var threshold = 8.15; var ssimThreshold = 0.9; - var taskInfo = await DbScoped.Sugar - .Queryable() + var taskInfo = await videoTaskDB.AsQueryable() .Where(s => s.Id == long.Parse(task)).FirstAsync(); if (string.IsNullOrEmpty(taskInfo.PPTVideoCode) || string.IsNullOrEmpty(taskInfo.PPTVideoUrl)) return; //视频切帧 @@ -55,11 +74,11 @@ namespace VideoAnalysisCore.AICore.FFMPGE } var ffmpeg = new Engine(FFmpegPath); var cToken = new CancellationToken(); - RedisExpand.SetTaskProgress(task, "Frame=>10%"); + redisManager.SetTaskProgress(task, "Frame=>10%"); foreach (string jpgFile in Directory.GetFiles(localPath, "*.jpg")) FileSystem.DeleteFile(jpgFile, UIOption.OnlyErrorDialogs, RecycleOption.DeletePermanently); - RedisExpand.SetTaskProgress(task, "Frame=>20%"); + redisManager.SetTaskProgress(task, "Frame=>20%"); await ffmpeg.ExecuteAsync($"-i {filePath} -vf \"fps=1/{intervalSec},scale=960:540\" {localPath}/{ExpandFunction.FrameName}%03d.jpg", cToken); @@ -67,7 +86,7 @@ namespace VideoAnalysisCore.AICore.FFMPGE var frameFiles = Directory.GetFiles(localPath, "*.jpg") .OrderBy(f => f) .ToList(); - RedisExpand.SetTaskProgress(task, "Frame=>80%"); + redisManager.SetTaskProgress(task, "Frame=>80%"); Image prevFrame = null; var keyFrames = new List(10) { 5}; foreach (var frameFile in frameFiles) @@ -103,8 +122,7 @@ namespace VideoAnalysisCore.AICore.FFMPGE } //写入数据库 var keyFramStr = keyFrames.Where(s => s != -1).ToJson(); - await DbScoped.Sugar - .Updateable() + await videoTaskDB.AsUpdateable() .SetColumns(it => it.PPTKeyFrame == keyFramStr) .Where(it => it.Id == taskID) .ExecuteCommandAsync(); @@ -117,7 +135,7 @@ namespace VideoAnalysisCore.AICore.FFMPGE /// /// /// - static double CalculateFrameDifference(Image img1, Image img2) + double CalculateFrameDifference(Image img1, Image img2) { // 统一调整为64x64 var resized1 = img1.Clone(x => x.Grayscale()); @@ -136,7 +154,7 @@ namespace VideoAnalysisCore.AICore.FFMPGE return diff / (double)(resized1.Width * resized1.Height); } - static double GetTimestampFromFileName(string filePath) + double GetTimestampFromFileName(string filePath) { string fileName = Path.GetFileNameWithoutExtension(filePath); return double.Parse(fileName.Split('_')[1]); @@ -146,7 +164,7 @@ namespace VideoAnalysisCore.AICore.FFMPGE /// /// /// - public static async Task RunAsync(string task) + public async Task RunAsync(string task) { await VideoKeyFrames(task); await Audio2WAV16KAsync(task); @@ -156,10 +174,9 @@ namespace VideoAnalysisCore.AICore.FFMPGE /// /// 任务id /// - public static async Task Audio2WAV16KAsync(string task) + public async Task Audio2WAV16KAsync(string task) { - var filePath = await DbScoped.Sugar - .Queryable() + var filePath = await videoTaskDB.AsQueryable() .Where(s => s.Id == long.Parse(task)) .Select(s=>s.LocalMediaPath).FirstAsync(); if (string.IsNullOrEmpty(filePath)) diff --git a/VideoAnalysisCore/AICore/GPT/ChatGPT/Chat_GPT.cs b/VideoAnalysisCore/AICore/GPT/ChatGPT/Chat_GPT.cs index 47fd99e..37ad969 100644 --- a/VideoAnalysisCore/AICore/GPT/ChatGPT/Chat_GPT.cs +++ b/VideoAnalysisCore/AICore/GPT/ChatGPT/Chat_GPT.cs @@ -23,17 +23,19 @@ namespace VideoAnalysisCore.AICore.GPT.ChatGPT private readonly Repository criteriaDB; private readonly Repository videoTaskDB; private readonly Repository knowledgeInfoDB; + private readonly RedisManager redisManager; /// /// 初始化 /// /// /// - public Chat_GPT(ChatGPTClient moonshotClient, Repository criteria, Repository videoTaskDB, Repository knowledgeInfoDB) + public Chat_GPT(ChatGPTClient moonshotClient, Repository criteria, Repository videoTaskDB, Repository knowledgeInfoDB, RedisManager redisManager) { this.chatClient = moonshotClient; criteriaDB = criteria; this.videoTaskDB = videoTaskDB; this.knowledgeInfoDB = knowledgeInfoDB; + this.redisManager = redisManager; } private static List MergeRes(VideoKnowRes[] timeBases) @@ -162,7 +164,7 @@ namespace VideoAnalysisCore.AICore.GPT.ChatGPT item.EndTime = (int)(questionRes[i + 1]?.StartTime ?? 0) - 1; } - await RedisExpand.Redis + await redisManager.Redis .HMSetAsync(RedisExpandKey.Task(task), "VideoKnows", questionRes); //var postMessages1 = @@ -181,7 +183,7 @@ namespace VideoAnalysisCore.AICore.GPT.ChatGPT ////questionRes1 = MergeRes(questionRes1).ToArray(); var gptRes = new TaskRes(captions); - await RedisExpand.Redis + await redisManager.Redis .HMSetAsync(RedisExpandKey.Task(task), "ChatAnalysis", gptRes); return gptRes; } @@ -203,13 +205,13 @@ namespace VideoAnalysisCore.AICore.GPT.ChatGPT }; var time = DateTime.Now.ToString("MMddHHmmss"); - RedisExpand.SetTaskGPTCached(task, time,chatRep); + redisManager.SetTaskGPTCached(task, time,chatRep); var chatResp = await chatClient.Chat(chatRep); var chatResContent = chatResp?.res; if (string.IsNullOrEmpty(chatResContent)) throw new Exception("GPT返回message无效结果"); if (chatResp != null) - RedisExpand.SetTaskGPTCached(task, time, new object[] { chatResp.Value.res, chatResp.Value.u }); + redisManager.SetTaskGPTCached(task, time, new object[] { chatResp.Value.res, chatResp.Value.u }); chatResContent = chatResContent?.Replace("字幕内容", "课堂情况"); chatResContent = chatResContent?.Replace("\n", ""); @@ -307,13 +309,13 @@ namespace VideoAnalysisCore.AICore.GPT.ChatGPT }; var time = DateTime.Now.ToString("MMddHHmmss"); - RedisExpand.SetTaskGPTCached(task, time, chatRep); + redisManager.SetTaskGPTCached(task, time, chatRep); var chatResp = await chatClient.Chat(chatRep); var chatResContent = chatResp?.res; if (string.IsNullOrEmpty(chatResContent)) throw new Exception("GPT返回message无效结果"); if (chatResp != null) - RedisExpand.SetTaskGPTCached(task, time, new object[] { chatResp.Value.res, chatResp.Value.u }); + redisManager.SetTaskGPTCached(task, time, new object[] { chatResp.Value.res, chatResp.Value.u }); chatResContent = chatResContent?.Replace("字幕内容", "课堂情况"); chatResContent = chatResContent?.Replace("\n", ""); @@ -413,7 +415,7 @@ namespace VideoAnalysisCore.AICore.GPT.ChatGPT .ExecuteCommandAsync(); } - await RedisExpand.Redis + await redisManager.Redis .HMSetAsync(RedisExpandKey.Task(task), "ChatAnalysis", gptRes); return gptRes; diff --git a/VideoAnalysisCore/AICore/GPT/DeepSeek/DeepSeekClient.cs b/VideoAnalysisCore/AICore/GPT/DeepSeek/DeepSeekClient.cs index dd7b7a8..5b2f239 100644 --- a/VideoAnalysisCore/AICore/GPT/DeepSeek/DeepSeekClient.cs +++ b/VideoAnalysisCore/AICore/GPT/DeepSeek/DeepSeekClient.cs @@ -33,10 +33,13 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek //private readonly string Path = "v1/chat/completions"; private readonly IHttpClientFactory _httpClientFactory; + private readonly RedisManager redisManager; - public DeepSeekGPTClient(IHttpClientFactory httpClientFactory) + + public DeepSeekGPTClient(IHttpClientFactory httpClientFactory, RedisManager redisManager) { _httpClientFactory = httpClientFactory; + this.redisManager = redisManager; } @@ -192,7 +195,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek messageBuilder1.Append(strReasoning); var steamCount = messageBuilder.Length + messageBuilder1.Length; if (++threshold%30==0) - RedisExpand.SetTaskProgress(chatReq.taskId, "steam=>"+ steamCount); + redisManager.SetTaskProgress(chatReq.taskId, "steam=>"+ steamCount); } catch (Exception e) { diff --git a/VideoAnalysisCore/AICore/GPT/DeepSeek/DeepSeek_GPT.cs b/VideoAnalysisCore/AICore/GPT/DeepSeek/DeepSeek_GPT.cs index f0c68ea..0103b72 100644 --- a/VideoAnalysisCore/AICore/GPT/DeepSeek/DeepSeek_GPT.cs +++ b/VideoAnalysisCore/AICore/GPT/DeepSeek/DeepSeek_GPT.cs @@ -14,7 +14,6 @@ using VideoAnalysisCore.Model.Enum; using Mapster; using System.Linq; using System.Security.Cryptography; -using static System.Collections.Specialized.BitVector32; using FFmpeg.NET.Services; using Aliyun.OSS; using Yitter.IdGenerator; @@ -31,6 +30,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek { private readonly DeepSeekGPTClient chatClient; private readonly Repository criteriaDB; + private readonly RedisManager redisManager; private readonly Repository videoTaskDB; private readonly Repository videoKonwPointDB; private readonly Repository videoQuestionDB; @@ -43,7 +43,9 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek /// /// /// - public DeepSeek_GPT(DeepSeekGPTClient moonshotClient, Repository criteria, Repository videoTaskDB, Repository knowledgeInfoDB, Repository videoKonwPointDB, SimpLetexClient simpLetexClient, Repository videoQuestionDB, OssClient ossClient, Repository videoQuestionKonwDB) + public DeepSeek_GPT(DeepSeekGPTClient moonshotClient, Repository criteria, Repository videoTaskDB, + Repository knowledgeInfoDB, Repository videoKonwPointDB, SimpLetexClient simpLetexClient, + Repository videoQuestionDB, OssClient ossClient, Repository videoQuestionKonwDB, RedisManager redisManager) { chatClient = moonshotClient; criteriaDB = criteria; @@ -54,6 +56,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek this.videoQuestionDB = videoQuestionDB; this.ossClient = ossClient; this.videoQuestionKonwDB = videoQuestionKonwDB; + this.redisManager = redisManager; } /// /// 获取内容对应的章节 @@ -151,7 +154,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek .SetColumns(it => it.Sections == fileNameInfoRes.授课章节) .Where(it => it.Id == taskInfo.Id) .ExecuteCommandAsync(); - await RedisExpand.Redis + await redisManager.Redis .HMSetAsync(RedisExpandKey.Task(task), "学科章节", fileNameInfoRes.授课章节); return fileNameInfoRes?.授课章节; @@ -354,7 +357,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek { var time = title + DateTime.Now.ToString("MMddHHmmss"); var redisCached = new object[2] { chatRep, null }; - RedisExpand.SetTaskGPTCached(task, time, chatRep); + redisManager.SetTaskGPTCached(task, time, chatRep); var chatResp = await chatClient.Chat(chatRep); var chatResContent = chatResp?.res; if (string.IsNullOrEmpty(chatResContent)) @@ -362,7 +365,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek if (chatResp != null) { redisCached[1] = new object[] { chatResp.Value.res, chatResp.Value.u, chatResp.Value.reasoning }; - RedisExpand.SetTaskGPTCached(task, time, redisCached); + redisManager.SetTaskGPTCached(task, time, redisCached); } chatResContent = chatResContent?.ExtractJsonStrings()?.FirstOrDefault(); chatResContent = chatResContent?.Replace("\n", ""); @@ -604,7 +607,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek { throw new Exception("重试次数过多!"); } - await RedisExpand.Redis + await redisManager.Redis .HMSetAsync(RedisExpandKey.Task(task), "VideoKnows", questionRes); return null; diff --git a/VideoAnalysisCore/AICore/SherpaOnnx/SenseVoice.cs b/VideoAnalysisCore/AICore/SherpaOnnx/SenseVoice.cs index 08038ea..db08f35 100644 --- a/VideoAnalysisCore/AICore/SherpaOnnx/SenseVoice.cs +++ b/VideoAnalysisCore/AICore/SherpaOnnx/SenseVoice.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.Options; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; using SherpaOnnx; using SqlSugar.IOC; using System; @@ -17,18 +18,40 @@ using static System.Runtime.InteropServices.JavaScript.JSType; namespace VideoAnalysisCore.AICore.SherpaOnnx { - public static class SenseVoice + public static class SenseVoiceExpand + { + + /// + /// 添加 SenseVoice 语音转文字 + /// + /// + public static void AddSenseVoiceExpand(this IServiceCollection services) + { + services.AddSingleton(); + } + } + public class SenseVoice { const string TransducerStr = "sherpa-onnx-streaming-zipformer-bilingual-zh-en-2023-02-20"; static OfflineRecognizer OR = default!; //static VoiceActivityDetector VAD = default!; static VadModelConfig VADModelConfig = default!; + public Repository videoTaskDB { get; set; } + + private readonly RedisManager redisManager; + + public SenseVoice(Repository videoTaskDB, RedisManager redisManager) + { + this.videoTaskDB = videoTaskDB; + this.redisManager = redisManager; + } + /// /// 初始化 SenseVoice /// /// 默认6线程 /// 是否使用gpu 报错请看安装CUDA环境 - public static void Init(int numThreads = 6, bool useGPU = false, bool useHotwords = false) + public void Init(int numThreads = 6, bool useGPU = false, bool useHotwords = false) { Console.WriteLine("初始化 SenseVoice"); OfflineRecognizerConfig config = new OfflineRecognizerConfig(); @@ -102,24 +125,19 @@ namespace VideoAnalysisCore.AICore.SherpaOnnx /// /// /// - public static async Task> RunTask(Stream s) + public async Task> RunTask(Stream s) { if (s is null) throw new Exception("音频路径 is null"); - return await TaskHandle(new WaveReader(s)); - - + return await TaskHandle(new WaveReader(s), null); } - - - /// /// 获取语音字幕 /// /// /// - public static async Task RunTask(string task) + public async Task RunTask(string task) { var filePath = Path.Combine(task.LocalPath(), "task.wav"); if (string.IsNullOrEmpty(filePath) || !File.Exists(filePath)) @@ -134,7 +152,7 @@ namespace VideoAnalysisCore.AICore.SherpaOnnx /// 任务id [默认Null] /// /// - public static async Task> TaskHandle(WaveReader reader, string? task = null) + public async Task> TaskHandle(WaveReader reader, string? task ) { if (OR is null) Init(); @@ -162,25 +180,30 @@ namespace VideoAnalysisCore.AICore.SherpaOnnx { //获取最新的发言片段 while (!VAD.IsEmpty()) - await VAD.ReadNext(res, totalSecond, task); + { + var p = await ReadNext(VAD,res, totalSecond); + if (p != null) redisManager.SetTaskProgress(task, p + "%"); + } } } VAD.Flush(); while (!VAD.IsEmpty()) - await VAD.ReadNext(res, totalSecond, task); + { + var p = await ReadNext(VAD, res, totalSecond); + if(p!= null) redisManager.SetTaskProgress(task, p + "%"); + } //如果携带任务ID if (!string.IsNullOrEmpty(task)) { Console.WriteLine(DateTime.Now + "=> SenseVoice 字幕数量" + res.Count); var captionsStr = res.ToJson(); - await DbScoped.Sugar - .Updateable() + await videoTaskDB.AsUpdateable() .SetColumns(it => it.Captions == captionsStr) .Where(it => it.Id == long.Parse(task)) .ExecuteCommandAsync(); - await RedisExpand.Redis.HMSetAsync(RedisExpandKey.Task(task), "Captions", res); + await redisManager.Redis.HMSetAsync(RedisExpandKey.Task(task), "Captions", res); //分析完成视频字幕后继续接收任务 - RedisExpand.NewTask(); + redisManager.NewTask(); } return res; } @@ -190,9 +213,9 @@ namespace VideoAnalysisCore.AICore.SherpaOnnx /// /// 字幕处理后写入数组 /// 总时长 - /// 所属任务id + /// 任务回调 /// - public static async Task ReadNext(this VoiceActivityDetector VAD, List res, float totalSecond, string? task = null) + public async Task ReadNext(VoiceActivityDetector VAD, List res, float totalSecond) { var segment = VAD.Front(); var sampleRate = VADModelConfig.SampleRate; @@ -202,13 +225,14 @@ namespace VideoAnalysisCore.AICore.SherpaOnnx using var stream = OR.CreateStream(); stream.AcceptWaveform(sampleRate, segment.Samples); OR.Decode(stream); + double? resP =null; if (!string.IsNullOrEmpty(stream.Result.Text)) { var text = stream.Result.Text.Trim(); if (text.Length == 1 && text == "。")// 检查字符是否只有一个句号 { VAD.Pop(); - return; + return resP; } res.Add(new() { @@ -216,10 +240,10 @@ namespace VideoAnalysisCore.AICore.SherpaOnnx Start = (float)Math.Round(startTime, 2, MidpointRounding.AwayFromZero), End = (float)Math.Round(startTime + duration, 2, MidpointRounding.AwayFromZero), }); - if (!string.IsNullOrEmpty(task)) - RedisExpand.SetTaskProgress(task, Math.Round((double)(startTime + duration) / (totalSecond) * 100,2)+"%"); + resP = Math.Round((double)(startTime + duration) / (totalSecond) * 100, 2); } VAD.Pop(); + return resP; } } } diff --git a/VideoAnalysisCore/AICore/SherpaOnnx/Speaker.cs b/VideoAnalysisCore/AICore/SherpaOnnx/Speaker.cs index d8ecb3e..747b99f 100644 --- a/VideoAnalysisCore/AICore/SherpaOnnx/Speaker.cs +++ b/VideoAnalysisCore/AICore/SherpaOnnx/Speaker.cs @@ -10,6 +10,7 @@ using System.Text.Json; using VideoAnalysisCore.Model.Enum; using Microsoft.Extensions.DependencyInjection; using UserCenter.Model.Enum; +using VideoAnalysisCore.Model.Dto; namespace VideoAnalysisCore.AICore.SherpaOnnx { @@ -73,17 +74,16 @@ namespace VideoAnalysisCore.AICore.SherpaOnnx if(i%20 !=0) return 1; var progress = (float)numProcessedChunks / numTotalChunks * 100; - RedisExpand.SetTaskProgress(task, progress); + //RedisExpand.SetTaskProgress(task, progress); return 1; }, nint.Zero); var res = segments.Select(s => new OfflineSpeakerRes(s)); - await RedisExpand.Redis.HSetAsync(RedisExpandKey.Task(task), "Speaker", res); + //await RedisExpand.Redis.HSetAsync(RedisExpandKey.Task(task), "Speaker", res); var speakerStr = res.ToJson(); - await DbScoped.Sugar - .Updateable() - .SetColumns(it => it.Speaker == speakerStr) - .Where(it => it.Id == long.Parse(task)) - .ExecuteCommandAsync(); + //await videoTaskDB.Updateable() + // .SetColumns(it => it.Speaker == speakerStr) + // .Where(it => it.Id == long.Parse(task)) + // .ExecuteCommandAsync(); } } diff --git a/VideoAnalysisCore/AICore/Whisper/WhisperHandle.cs b/VideoAnalysisCore/AICore/Whisper/WhisperHandle.cs index 9f91a5d..2d453dc 100644 --- a/VideoAnalysisCore/AICore/Whisper/WhisperHandle.cs +++ b/VideoAnalysisCore/AICore/Whisper/WhisperHandle.cs @@ -45,7 +45,7 @@ namespace VideoAnalysisCore.AICore.Whisper { res.Add(new WhisperResDto(segment)); } - RedisExpand.Redis.HMSet(RedisExpandKey.Task(task), "Captions", res); + //RedisExpand.Redis.HMSet(RedisExpandKey.Task(task), "Captions", res); } /// /// 检测语言的方法 diff --git a/VideoAnalysisCore/Common/DownloadFile.cs b/VideoAnalysisCore/Common/DownloadFile.cs index f1e4f71..7d95748 100644 --- a/VideoAnalysisCore/Common/DownloadFile.cs +++ b/VideoAnalysisCore/Common/DownloadFile.cs @@ -93,14 +93,16 @@ namespace VideoAnalysisCore.Common private readonly Repository videoTaskDB; private readonly Repository packageInfoTaskDB; private readonly Client vodClient; + private readonly RedisManager redisManager; readonly string taskVideoName = "task.mp4"; readonly string taskPPTVideoName = "ppt.mp4"; - public DownloadFile(Repository videoTaskDB, Client vodClient, Repository nackageInfoTaskDB) + public DownloadFile(Repository videoTaskDB, Client vodClient, Repository nackageInfoTaskDB, RedisManager redisManager) { this.videoTaskDB = videoTaskDB; this.vodClient = vodClient; this.packageInfoTaskDB = nackageInfoTaskDB; + this.redisManager = redisManager; } // 根据 Content-Type 映射文件后缀 @@ -187,7 +189,7 @@ namespace VideoAnalysisCore.Common if (!string.IsNullOrEmpty(taskInfo.PPTVideoUrl)) { await Download(taskInfo.PPTVideoUrl, localPath, taskPPTVideoName, - (s, e) => RedisExpand.SetTaskProgress(task, "PPT->" + Math.Round(e.ProgressPercentage, 1) + (s, e) => redisManager.SetTaskProgress(task, "PPT->" + Math.Round(e.ProgressPercentage, 1) )); //try //{ @@ -217,7 +219,7 @@ namespace VideoAnalysisCore.Common { //下载原视频 await Download(fileUrl, localPath, taskVideoName, - (s, e) => RedisExpand.SetTaskProgress(task, Math.Round(e.ProgressPercentage,1) + (s, e) => redisManager.SetTaskProgress(task, Math.Round(e.ProgressPercentage,1) )); } catch diff --git a/VideoAnalysisCore/Common/Expand/SqlSugarExpand.cs b/VideoAnalysisCore/Common/Expand/SqlSugarExpand.cs index d1ac4fc..ea2d7cc 100644 --- a/VideoAnalysisCore/Common/Expand/SqlSugarExpand.cs +++ b/VideoAnalysisCore/Common/Expand/SqlSugarExpand.cs @@ -44,7 +44,7 @@ namespace VideoAnalysisCore.Common.Expand DbType = s.SqlType, IsAutoCloseConnection = true })); - services.AddScoped(typeof(Repository<>)); + services.AddTransient(typeof(Repository<>)); //注入SqlSugar 主库 services.AddSqlSugar(dbList); diff --git a/VideoAnalysisCore/Common/RedisExpand.cs b/VideoAnalysisCore/Common/RedisExpand.cs index 7d8942e..24c1ef6 100644 --- a/VideoAnalysisCore/Common/RedisExpand.cs +++ b/VideoAnalysisCore/Common/RedisExpand.cs @@ -1,6 +1,7 @@ using FreeRedis; using FreeRedis.Internal; using Microsoft.Extensions.DependencyInjection; +using Microsoft.IdentityModel.Tokens; using NetTaste; using Newtonsoft.Json.Schema; using SqlSugar.IOC; @@ -22,7 +23,6 @@ using VideoAnalysisCore.AICore.Whisper; using VideoAnalysisCore.Model; using VideoAnalysisCore.Model.Dto; using VideoAnalysisCore.Model.Enum; -using static System.Runtime.InteropServices.JavaScript.JSType; namespace VideoAnalysisCore.Common { @@ -31,6 +31,7 @@ namespace VideoAnalysisCore.Common /// public static class RedisExpandKey { + /// /// 基础key /// @@ -72,45 +73,112 @@ namespace VideoAnalysisCore.Common public static string Task(object taskId) => BaseKey + "Task:" + taskId; public static string IDTask => BaseKey + "Services:" + AppCommon.Config.ID; public static string TaskGPT(object taskId) => Task(taskId) + ":GPTCached"; + /// + /// 初始化 redis + /// 需要在初始化配置文件时候调用 + /// + public static void AddTaskSubscribe(this IServiceCollection service) + { + Console.WriteLine($"{DateTime.Now}=>初始化 Redis任务队列"); + service.AddSingleton(); + } + public static void AddRedisExpand(this IServiceCollection service) + { + Console.WriteLine($"{DateTime.Now}=>初始化 Redis"); + var redis = new RedisClient(AppCommon.Config.Redis.ConnectionString); + redis.Serialize = obj => JsonSerializer.Serialize(obj); + redis.Deserialize = (json, type) => JsonSerializer.Deserialize(json, type); + service.AddSingleton(redis); + service.AddSingleton(); + } + } + + public class RedisInit + { + + public FFMPGEHandle FFMPGE { get; set; } + public SenseVoice senseVoice { get; set; } + public RedisManager redisManager { get; set; } + + public RedisInit(FFMPGEHandle fFMPGE, SenseVoice senseVoice, RedisManager redisManager) + { + FFMPGE = fFMPGE; + this.senseVoice = senseVoice; + this.redisManager = redisManager; + Init(); + redisManager.InitChannel(); + } + + public void Init() + { + var SubscribeList = RedisManager.SubscribeList; + SubscribeList.Add(RedisChannelEnum.下载文件, (task) => + { + using var scope = AppCommon.Services?.CreateScope(); + if (scope is null || scope.ServiceProvider.GetService() is null) + throw new Exception("DownloadFile 未注入"); + else + return scope.ServiceProvider.GetService()?.RunTask(task) ?? Task.CompletedTask; + }); + SubscribeList.Add(RedisChannelEnum.分离音频, FFMPGE.RunAsync); + SubscribeList.Add(RedisChannelEnum.解析字幕, senseVoice.RunTask); + //SubscribeList.Add(RedisChannelEnum.解析说话人,Speaker.Run); + SubscribeList.Add(RedisChannelEnum.AI课程类型, + (task) => + { + using var scope = AppCommon.Services?.CreateScope(); + if (scope is null || scope.ServiceProvider.GetService() is null) + throw new Exception("IBserGPT 未注入"); + else + return scope.ServiceProvider.GetService()?.GetVideoType(task) ?? Task.CompletedTask; + }); + SubscribeList.Add(RedisChannelEnum.AI模型分析, (task) => + { + using var scope = AppCommon.Services?.CreateScope(); + if (scope is null || scope.ServiceProvider.GetService() is null) + throw new Exception("IBserGPT 未注入"); + else + return scope.ServiceProvider.GetService()?.GetKnow(task) ?? Task.CompletedTask; + }); + SubscribeList.Add(RedisChannelEnum.AI分析试题, (task) => + { + using var scope = AppCommon.Services?.CreateScope(); + if (scope is null || scope.ServiceProvider.GetService() is null) + throw new Exception("IBserGPT 未注入"); + else + return scope.ServiceProvider.GetService()?.GetVideoQuestion(task) ?? Task.CompletedTask; + }); + SubscribeList.Add(RedisChannelEnum.结束任务, redisManager.TaskEnd); + + } } /// /// redis拓展 /// - public static class RedisExpand + public class RedisManager { - - /// - /// redis 连接 - /// - public static RedisClient Redis = new RedisClient(AppCommon.Config.Redis.ConnectionString); + public static bool StopTask { get; set; } = false; public static Dictionary> SubscribeList = new Dictionary>(); /// /// 队列池 /// static SubscribeListObject? Subscribe; + public RedisClient Redis { get; set; } + public Repository videoTaskDB { get; set; } - /// - /// 初始化 redis - /// 需要在初始化配置文件时候调用 - /// - public static void AddRedisExpand(this IServiceCollection service) + public RedisManager(RedisClient redis, Repository videoTaskDB) { - Console.WriteLine($"{DateTime.Now}=>初始化 Redis"); - Redis.Serialize = obj => JsonSerializer.Serialize(obj); - Redis.Deserialize = (json, type) => JsonSerializer.Deserialize(json, type); - Task.Run(() => - { - Thread.Sleep(1000 * 10); - InitChannel(); - }); + Redis = redis; + this.videoTaskDB = videoTaskDB; } + /// /// 缓存GPT任务缓存 /// /// - public static void SetTaskGPTCached(object taskId,string time, object? data) + public void SetTaskGPTCached(object taskId,string time, object? data) { Redis.Set(RedisExpandKey.TaskGPT(taskId) + ":" + time, data, 3600 * 24); } @@ -118,7 +186,7 @@ namespace VideoAnalysisCore.Common /// 加入到消费队列 /// /// - public static void JoinQueue(params long[] taskIds) + public void JoinQueue(params long[] taskIds) { //事务 if (taskIds is null || taskIds.Length == 0) return; @@ -133,7 +201,7 @@ namespace VideoAnalysisCore.Common /// 获取任务进度 /// /// - public static float GetTaskProgress(object taskId) + public float GetTaskProgress(object taskId) { return Redis.HMGet(RedisExpandKey.Task(taskId), "Progress")[0]; } @@ -142,7 +210,7 @@ namespace VideoAnalysisCore.Common /// /// 进度百分比 /// - public static void SetTaskProgress(object taskId, object p) + public void SetTaskProgress(object taskId, object p) { Redis.HMSet(RedisExpandKey.Task(taskId), "Progress", p.ToString()); @@ -152,7 +220,7 @@ namespace VideoAnalysisCore.Common /// /// 枚举 /// 任务id - public static async Task InsertChannel(RedisChannelEnum @enum, object taskId) + public async Task InsertChannel(RedisChannelEnum @enum, object taskId) { if (taskId is null) throw new Exception("taskId为空"); if (Redis is null) throw new Exception("redis未初始化"); @@ -188,7 +256,7 @@ namespace VideoAnalysisCore.Common } } - public static async Task TaskEnd(string task) + public async Task TaskEnd(string task) { var tId = long.Parse(task); //var gptRes = (await Redis @@ -197,8 +265,8 @@ namespace VideoAnalysisCore.Common // throw new Exception("未能读取到GPT处理结果"); //删除任务执行状态 await Redis.LRemAsync(RedisExpandKey.IDTask,1,task); - var taskData = await DbScoped.Sugar.Queryable() - .FirstAsync(s => s.Id == tId); + var taskData = await videoTaskDB + .GetFirstAsync(s => s.Id == tId); if (taskData.Captions == "[]") taskData.Captions = (await Redis.HMGetAsync(RedisExpandKey.Task(task), "Captions")).First(); //if (taskData.Speaker == "[]") @@ -211,7 +279,7 @@ namespace VideoAnalysisCore.Common taskData.ErrorMessage = string.Empty; taskData.LastEnum = RedisChannelEnum.结束任务; taskData.EndTime = DateTime.Now; - await DbScoped.Sugar.Updateable(taskData) + await videoTaskDB.AsUpdateable(taskData) .UpdateColumns(it => new { //it.ChatAnalysis, @@ -230,56 +298,36 @@ namespace VideoAnalysisCore.Common /// /// 初始化 队列 任务 /// - public static async void InitChannel() + public async void InitChannel() { if (Redis is null) throw new Exception("redis未初始化"); - SubscribeList.Add(RedisChannelEnum.下载文件, (task) => - { - using var scope = AppCommon.Services?.CreateScope(); - if (scope is null || scope.ServiceProvider.GetService() is null) - throw new Exception("DownloadFile 未注入"); - else - return scope.ServiceProvider.GetService()?.RunTask(task) ?? Task.CompletedTask; - }); - SubscribeList.Add(RedisChannelEnum.分离音频, FFMPGEHandle.RunAsync); - SubscribeList.Add(RedisChannelEnum.解析字幕, SenseVoice.RunTask); - //SubscribeList.Add(RedisChannelEnum.解析说话人,Speaker.Run); - SubscribeList.Add(RedisChannelEnum.AI课程类型, - (task) => - { - using var scope = AppCommon.Services?.CreateScope(); - if (scope is null || scope.ServiceProvider.GetService() is null) - throw new Exception("IBserGPT 未注入"); - else - return scope.ServiceProvider.GetService()?.GetVideoType(task) ?? Task.CompletedTask; - }); - SubscribeList.Add(RedisChannelEnum.AI模型分析, (task) => - { - using var scope = AppCommon.Services?.CreateScope(); - if (scope is null || scope.ServiceProvider.GetService() is null) - throw new Exception("IBserGPT 未注入"); - else - return scope.ServiceProvider.GetService()?.GetKnow(task) ?? Task.CompletedTask; - }); - SubscribeList.Add(RedisChannelEnum.AI分析试题, (task) => - { - using var scope = AppCommon.Services?.CreateScope(); - if (scope is null || scope.ServiceProvider.GetService() is null) - throw new Exception("IBserGPT 未注入"); - else - return scope.ServiceProvider.GetService()?.GetVideoQuestion(task) ?? Task.CompletedTask; - }); - SubscribeList.Add(RedisChannelEnum.结束任务, TaskEnd); - ReceivingTaskAsync(); + //处理之前程序结束前未能执行完的情况 + var oldTaskCount = Redis.LLen(RedisExpandKey.IDTask); + if (oldTaskCount > 0) + { + var oldTaskArr = Redis.LRange(RedisExpandKey.IDTask, 0, oldTaskCount); + Redis.LTrim(RedisExpandKey.IDTask, 1, 0);//删除 redis 列表 + foreach (var oldTask in oldTaskArr) + { + Console.WriteLine(DateTime.Now.ToString("HH:mm:ss") + "-------------> 接收上次未完成任务 " + oldTask); + await ClearTaskError(long.Parse(oldTask)); + var lastEnum = (await Redis.HMGetAsync(RedisExpandKey.Task(oldTask), "LastEnum")).FirstOrDefault(); + await InsertChannel(lastEnum, oldTask); + } + } + else + { + Console.WriteLine(DateTime.Now.ToString("HH:mm:ss") + "-------------> 接收新任务!"); + ReceivingTaskAsync(); + } } - public static bool StopTask { get; set; } = false; /// /// 停止接收新任务 /// - public static void StopTaskAsync() + public void StopTaskAsync() { StopTask = true; try @@ -297,7 +345,7 @@ namespace VideoAnalysisCore.Common /// /// 开始接收新任务 /// - public static void RestartTask() + public void RestartTask() { StopTask = false; NewTask(); @@ -306,7 +354,7 @@ namespace VideoAnalysisCore.Common /// 重新执行新任务 /// /// - public static void NewTask() + public void NewTask() { // 取消 消费机的任务订阅 if (StopTask) @@ -320,7 +368,7 @@ namespace VideoAnalysisCore.Common /// /// 重新接收新任务 /// - public static void ReceivingTaskAsync() + public void ReceivingTaskAsync() { if (AppCommon.Config.TaskSetting.IS_Server) { @@ -329,15 +377,6 @@ namespace VideoAnalysisCore.Common } Task.Run(async () => { - var oldTask = await Redis.LPopAsync(RedisExpandKey.IDTask); - if (!string.IsNullOrEmpty(oldTask)) - { - Console.WriteLine(DateTime.Now.ToString("HH:mm:ss") + "-------------> 接收重试任务 " + oldTask); - await ClearTaskError(long.Parse(oldTask)); - var lastEnum = (await Redis.HMGetAsync(RedisExpandKey.Task(oldTask), "LastEnum")).FirstOrDefault(); - await InsertChannel(lastEnum, oldTask); - return; - } lock (Redis) { if (Subscribe?.IsUnsubscribed == false)//排除重试机制后 多次接收任务导致内存泄露 @@ -363,7 +402,7 @@ namespace VideoAnalysisCore.Common /// /// /// - public static async Task SetTaskErrorMessage(long taskID, Exception? ex) + public async Task SetTaskErrorMessage(long taskID, Exception? ex) { var error = string.Empty; if (ex != null) @@ -386,17 +425,17 @@ namespace VideoAnalysisCore.Common /// /// /// - public static async Task ClearTaskError(long taskID) =>await SetTaskError(taskID, string.Empty); + public async Task ClearTaskError(long taskID) =>await SetTaskError(taskID, string.Empty); /// /// 修改任务的错误信息 /// /// /// /// - public static async Task SetTaskError(long taskID, string? error) + public async Task SetTaskError(long taskID, string? error) { Redis.HMSet(RedisExpandKey.Task(taskID), "ErrorMessage", error); - return await DbScoped.Sugar.Updateable() + return await videoTaskDB.AsUpdateable() .SetColumns(it => it.ErrorMessage == error)//SetColumns是可以叠加的 写2个就2个字段赋值 .Where(it => it.Id == taskID) .ExecuteCommandAsync() == 1; @@ -408,7 +447,7 @@ namespace VideoAnalysisCore.Common /// /// /// - public static async Task TouchChannel(RedisChannelEnum key, string taskId, Func action = null) + public async Task TouchChannel(RedisChannelEnum key, string taskId, Func action = null) { if (taskId is null) return; var tID = long.Parse(taskId); @@ -424,7 +463,7 @@ namespace VideoAnalysisCore.Common Redis.HMSet(RedisExpandKey.Task(taskId), "Progress", 0); lock (Redis) { - DbScoped.SugarScope.Updateable() + videoTaskDB.AsUpdateable() .SetColumns(it => it.LastEnum == key) .Where(it => it.Id == tID) .ExecuteCommand(); diff --git a/VideoAnalysisCore/Common/Repository.cs b/VideoAnalysisCore/Common/Repository.cs index 2281a9b..37f0cc6 100644 --- a/VideoAnalysisCore/Common/Repository.cs +++ b/VideoAnalysisCore/Common/Repository.cs @@ -24,16 +24,16 @@ namespace VideoAnalysisCore.Common if (CID.ContainsKey(t)) { base.Context = CID[t]!=null - ? DbScoped.SugarScope.GetConnectionScope(CID[t]) - : DbScoped.SugarScope; + ? DbScoped.Sugar.GetConnectionScope(CID[t]) + : DbScoped.Sugar; return; } var c = t.GetCustomAttribute(); if (!CID.ContainsKey(t)) CID.Add(t, c?.configId); base.Context = c != null - ? DbScoped.SugarScope.GetConnectionScope(c.configId) - : DbScoped.SugarScope; + ? DbScoped.Sugar.GetConnectionScope(c.configId) + : DbScoped.Sugar; } } } diff --git a/VideoAnalysisCore/Controllers/ApiController.cs b/VideoAnalysisCore/Controllers/ApiController.cs index 10ce01f..8dbba4e 100644 --- a/VideoAnalysisCore/Controllers/ApiController.cs +++ b/VideoAnalysisCore/Controllers/ApiController.cs @@ -28,15 +28,19 @@ namespace VideoAnalysisCore.Controllers { private readonly IMapper mp; private readonly Repository videoTaskDB; + private readonly RedisManager redisManager; private readonly Repository videoKonwDB; private readonly Repository courseInfoDB; + public readonly SenseVoice senseVoice; public ApiController(Repository videoTaskDB, - IMapper mp, Repository videoKonwDB, Repository courseInfoDB) + IMapper mp, Repository videoKonwDB, Repository courseInfoDB, RedisManager redisManager, SenseVoice senseVoice) { this.videoTaskDB = videoTaskDB; this.mp = mp; this.videoKonwDB = videoKonwDB; this.courseInfoDB = courseInfoDB; + this.redisManager = redisManager; + this.senseVoice = senseVoice; } private string GetClientIpAddress() @@ -82,9 +86,9 @@ namespace VideoAnalysisCore.Controllers public IActionResult StartTask(bool task) { if(task) - RedisExpand.RestartTask(); + redisManager.RestartTask(); else - RedisExpand.StopTaskAsync(); + redisManager.StopTaskAsync(); return Ok(); } /// @@ -100,7 +104,7 @@ namespace VideoAnalysisCore.Controllers using HttpClient client = new HttpClient(); // GETȡļ using var networkStream = await client.GetStreamAsync(url); - var res = await SenseVoice.RunTask(networkStream); + var res = await senseVoice.RunTask(networkStream); return Ok(res); } catch (Exception ex) @@ -117,7 +121,7 @@ namespace VideoAnalysisCore.Controllers public async Task AudioRecognition(IFormFile file) { using var s = file.OpenReadStream(); - var res = await SenseVoice.RunTask(s); + var res = await senseVoice.RunTask(s); return Ok(res); } @@ -204,8 +208,8 @@ namespace VideoAnalysisCore.Controllers .GetProperties(BindingFlags.Public | BindingFlags.Instance) .ToDictionary(s => s.Name, s => s.GetValue(task)); await videoTaskDB.InsertAsync(task); - RedisExpand.Redis.HMSet(RedisExpandKey.Task(task.Id), hashEntries); - RedisExpand.Redis.LPush(RedisExpandKey.ChannelKey, task.Id); + redisManager.Redis.HMSet(RedisExpandKey.Task(task.Id), hashEntries); + redisManager.Redis.LPush(RedisExpandKey.ChannelKey, task.Id); return Ok(task.Id); } diff --git a/VideoAnalysisCore/Controllers/LJZK_Controller.cs b/VideoAnalysisCore/Controllers/LJZK_Controller.cs index b3cf309..ee45ae9 100644 --- a/VideoAnalysisCore/Controllers/LJZK_Controller.cs +++ b/VideoAnalysisCore/Controllers/LJZK_Controller.cs @@ -38,10 +38,11 @@ namespace VideoAnalysisCore.Controllers private readonly Repository nodePackageInfoDB; private readonly Repository videoQuestionDB; private readonly Repository videoQuestionKonwDB; + private readonly RedisManager redisManager; public LJZK_Controller(IMapper mp, Repository nodesubscriptionDB, Repository videoTaskDB = null, Repository videoKonwPointDB = null - , Repository nodePackageInfoDB = null, Repository videoQuestionDB = null, Repository videoQuestionKonwDB = null, Repository courseInfoDB = null) + , Repository nodePackageInfoDB = null, Repository videoQuestionDB = null, Repository videoQuestionKonwDB = null, Repository courseInfoDB = null, RedisManager redisManager = null) { this.mp = mp; this.nodesubscriptionDB = nodesubscriptionDB; @@ -51,6 +52,7 @@ namespace VideoAnalysisCore.Controllers this.videoQuestionDB = videoQuestionDB; this.videoQuestionKonwDB = videoQuestionKonwDB; this.courseInfoDB = courseInfoDB; + this.redisManager = redisManager; } @@ -125,7 +127,7 @@ namespace VideoAnalysisCore.Controllers if (videos is null || videos.Count == 0) return Ok(); var ids = videos.Select(s => s.Id).ToArray(); - RedisExpand.JoinQueue(ids); + redisManager.JoinQueue(ids); return Ok(); } diff --git a/VideoAnalysisCore/Job/NodeSubscriptionJob.cs b/VideoAnalysisCore/Job/NodeSubscriptionJob.cs index dc5d1c3..25adac9 100644 --- a/VideoAnalysisCore/Job/NodeSubscriptionJob.cs +++ b/VideoAnalysisCore/Job/NodeSubscriptionJob.cs @@ -36,76 +36,76 @@ namespace VideoAnalysisCore.Job public async Task Invoke() { throw new Exception("已经弃用"); - Console.WriteLine($"{DateTime.Now} 执行=>文件节点订阅"); + // Console.WriteLine($"{DateTime.Now} 执行=>文件节点订阅"); - var videoIdArr = videotaskDB.AsQueryable().Select(v => v.TagId).Distinct().ToArray(); - var tasks = await nodesubscriptionDB.GetListAsync(s => s.Enable && s.Subject ==SubjectEnum.数学); - foreach (var item in tasks) - { - var fileNodeId = item.NodeId; - var data = attachmentsDB.Context.Ado - .SqlQuery($""" - SELECT top {TopLength} - * - FROM - Attachments - WHERE - Id IN ( - SELECT - AttachmentsId - FROM - Material - WHERE - id IN ( - SELECT - MaterialId - FROM - FileContentMaterial - WHERE - FileContentId IN ( SELECT id FROM FileContent WHERE BagId IN ( SELECT Id FROM FileDirectory WHERE Id={fileNodeId} AND types = 1 AND DeleteState = 0 ) ) - AND DeleteState = 0 - AND ( MaterialName NOT LIKE '%PPT%' OR MaterialName NOT LIKE '%ppt%' ) - ) - ) - AND Type = '录播视频' - AND ( - NAME NOT LIKE '%PPT%' - OR NAME NOT LIKE '%ppt%' - ) and id>{item.LastId} - """); - if (data is null || data.Count == 0) - continue; - Console.WriteLine($"{DateTime.Now} 视频订阅=>Node:{item.NodeId} 数量{data.Count}"); + // var videoIdArr = videotaskDB.AsQueryable().Select(v => v.TagId).Distinct().ToArray(); + // var tasks = await nodesubscriptionDB.GetListAsync(s => s.Enable && s.Subject ==SubjectEnum.数学); + // foreach (var item in tasks) + // { + // var fileNodeId = item.NodeId; + // var data = attachmentsDB.Context.Ado + // .SqlQuery($""" + //SELECT top {TopLength} + // * + //FROM + // Attachments + //WHERE + // Id IN ( + // SELECT + // AttachmentsId + // FROM + // Material + // WHERE + // id IN ( + // SELECT + // MaterialId + // FROM + // FileContentMaterial + // WHERE + // FileContentId IN ( SELECT id FROM FileContent WHERE BagId IN ( SELECT Id FROM FileDirectory WHERE Id={fileNodeId} AND types = 1 AND DeleteState = 0 ) ) + // AND DeleteState = 0 + // AND ( MaterialName NOT LIKE '%PPT%' OR MaterialName NOT LIKE '%ppt%' ) + // ) + // ) + // AND Type = '录播视频' + // AND ( + // NAME NOT LIKE '%PPT%' + // OR NAME NOT LIKE '%ppt%' + // ) and id>{item.LastId} + //"""); + // if (data is null || data.Count == 0) + // continue; + // Console.WriteLine($"{DateTime.Now} 视频订阅=>Node:{item.NodeId} 数量{data.Count}"); - var videos = new List(data.Count); - foreach (var s in data) - { - if (videoIdArr.Contains(s.VideoCode)) - continue; - //videos.Add(new VideoTask() - //{ - // Id = YitIdHelper.NextId(), - // ComeFrom = "127.0.0.1", - // ApiToken = "", - // //Type = item.TaskType, - // Subject = item.Subject, - // Tag = item.NodeId.ToString(), - // TagId = s.VideoCode, - // MediaUrl = string.Empty, - //}); - } - var maxId = data.Max(s => s.Id); - //入库 更新最后扫描记录 - await nodesubscriptionDB.AsUpdateable() - .SetColumns(it => it.LastId == maxId) - .Where(it => it.Id == item.Id) - .ExecuteCommandAsync(); - await videotaskDB.InsertRangeAsync(videos); - var ids = videos.Select(s => s.Id).ToArray(); - RedisExpand.JoinQueue(ids); + // var videos = new List(data.Count); + // foreach (var s in data) + // { + // if (videoIdArr.Contains(s.VideoCode)) + // continue; + // //videos.Add(new VideoTask() + // //{ + // // Id = YitIdHelper.NextId(), + // // ComeFrom = "127.0.0.1", + // // ApiToken = "", + // // //Type = item.TaskType, + // // Subject = item.Subject, + // // Tag = item.NodeId.ToString(), + // // TagId = s.VideoCode, + // // MediaUrl = string.Empty, + // //}); + // } + // var maxId = data.Max(s => s.Id); + // //入库 更新最后扫描记录 + // await nodesubscriptionDB.AsUpdateable() + // .SetColumns(it => it.LastId == maxId) + // .Where(it => it.Id == item.Id) + // .ExecuteCommandAsync(); + // await videotaskDB.InsertRangeAsync(videos); + // var ids = videos.Select(s => s.Id).ToArray(); + // RedisExpand.JoinQueue(ids); - } + // } } } }