parent
94cde3af70
commit
0edf143f8a
|
|
@ -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 =>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ namespace Learn.VideoAnalysis.Components.Pages
|
|||
[Inject] private ConfirmService ComfirmService { get; set; } = default!;
|
||||
[Inject] private Repository<VideoTask> 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<int>(RedisExpandKey.Task(query.Id), "LastEnum")).FirstOrDefault();
|
||||
(await redisManager.Redis.HMGetAsync<int>(RedisExpandKey.Task(query.Id), "LastEnum")).FirstOrDefault();
|
||||
selectEnum = selectDefaultValue;
|
||||
reStartTask = query;
|
||||
modalShow = true;
|
||||
|
|
@ -69,9 +71,9 @@ namespace Learn.VideoAnalysis.Components.Pages
|
|||
/// <param name="query"></param>
|
||||
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<string>(RedisExpandKey.Task(item.Id),
|
||||
var data = redisManager.Redis.HMGet<string>(RedisExpandKey.Task(item.Id),
|
||||
"Progress", "LastEnum", "StartTime", "ErrorMessage");
|
||||
item.Progress = data[0];
|
||||
item.LastEnum = data[1] == null ?default:data[1].ToEnum<RedisChannelEnum>() ?? default;
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ namespace Learn.VideoAnalysis.Components.Pages
|
|||
[Inject] private Repository<VideoQuestion> videoQuestionDB { get; set; } = default!;
|
||||
[Inject] private Repository<VideoQuestionKonw> videoQuestionKonwDB { get; set; } = default!;
|
||||
[Inject] private Repository<VideoKonwPoint> 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<SenseVoiceRes[]>(nowTask.Captions);
|
||||
var captionsArr1 = JsonSerializer.Deserialize<SenseVoiceRes[]>(nowTask.CaptionsAI??"[]") ;
|
||||
RedisExpand.Redis.HMGet<SenseVoiceRes[]>(RedisExpandKey.Task(taskId), "Captions").FirstOrDefault();
|
||||
redisManager.Redis.HMGet<SenseVoiceRes[]>(RedisExpandKey.Task(taskId), "Captions").FirstOrDefault();
|
||||
|
||||
var konwArr = await videoKonwPointDB.AsQueryable()
|
||||
.Where(s => s.VideoTaskId == nowTask.Id)
|
||||
|
|
|
|||
|
|
@ -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<IBserGPT, Chat_GPT>();
|
||||
builder.Services.AddSingleton<IBserGPT, DeepSeek_GPT>();
|
||||
|
||||
builder.Services.AddTaskSubscribe();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
|
|
@ -119,6 +124,7 @@ namespace Learn.VideoAnalysis
|
|||
|
||||
// Configure the HTTP request pipeline.
|
||||
|
||||
_ = app.Services.GetRequiredService<RedisInit>();
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
app.UseExceptionHandler("/Error");
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// 添加跨域拓展
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
public static void AddFFMPGEExpand(this IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton<FFMPGEHandle>();
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Ffmpeg处理程序
|
||||
/// </summary>
|
||||
|
|
@ -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<VideoTask> videoTaskDB { get; set; }
|
||||
private RedisManager redisManager { get; set; }
|
||||
public FFMPGEHandle(RedisManager redisManager, Repository<VideoTask> videoTaskDB)
|
||||
{
|
||||
this.redisManager = redisManager;
|
||||
this.videoTaskDB = videoTaskDB;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 识别视频关键帧
|
||||
/// </summary>
|
||||
/// <param name="task">任务id</param>
|
||||
/// <returns></returns>
|
||||
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<VideoTask>()
|
||||
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<Rgb24> prevFrame = null;
|
||||
var keyFrames = new List<int>(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<VideoTask>()
|
||||
await videoTaskDB.AsUpdateable()
|
||||
.SetColumns(it => it.PPTKeyFrame == keyFramStr)
|
||||
.Where(it => it.Id == taskID)
|
||||
.ExecuteCommandAsync();
|
||||
|
|
@ -117,7 +135,7 @@ namespace VideoAnalysisCore.AICore.FFMPGE
|
|||
/// <param name="img1"></param>
|
||||
/// <param name="img2"></param>
|
||||
/// <returns></returns>
|
||||
static double CalculateFrameDifference(Image<Rgb24> img1, Image<Rgb24> img2)
|
||||
double CalculateFrameDifference(Image<Rgb24> img1, Image<Rgb24> 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
|
|||
/// </summary>
|
||||
/// <param name="task"></param>
|
||||
/// <returns></returns>
|
||||
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
|
|||
/// </summary>
|
||||
/// <param name="task">任务id</param>
|
||||
/// <returns></returns>
|
||||
public static async Task Audio2WAV16KAsync(string task)
|
||||
public async Task Audio2WAV16KAsync(string task)
|
||||
{
|
||||
var filePath = await DbScoped.Sugar
|
||||
.Queryable<VideoTask>()
|
||||
var filePath = await videoTaskDB.AsQueryable()
|
||||
.Where(s => s.Id == long.Parse(task))
|
||||
.Select(s=>s.LocalMediaPath).FirstAsync();
|
||||
if (string.IsNullOrEmpty(filePath))
|
||||
|
|
|
|||
|
|
@ -23,17 +23,19 @@ namespace VideoAnalysisCore.AICore.GPT.ChatGPT
|
|||
private readonly Repository<CourseGradingCriteria> criteriaDB;
|
||||
private readonly Repository<VideoTask> videoTaskDB;
|
||||
private readonly Repository<KnowledgeInfo> knowledgeInfoDB;
|
||||
private readonly RedisManager redisManager;
|
||||
/// <summary>
|
||||
/// 初始化
|
||||
/// </summary>
|
||||
/// <param name="moonshotClient"></param>
|
||||
/// <param name="logger"></param>
|
||||
public Chat_GPT(ChatGPTClient moonshotClient, Repository<CourseGradingCriteria> criteria, Repository<VideoTask> videoTaskDB, Repository<KnowledgeInfo> knowledgeInfoDB)
|
||||
public Chat_GPT(ChatGPTClient moonshotClient, Repository<CourseGradingCriteria> criteria, Repository<VideoTask> videoTaskDB, Repository<KnowledgeInfo> knowledgeInfoDB, RedisManager redisManager)
|
||||
{
|
||||
this.chatClient = moonshotClient;
|
||||
criteriaDB = criteria;
|
||||
this.videoTaskDB = videoTaskDB;
|
||||
this.knowledgeInfoDB = knowledgeInfoDB;
|
||||
this.redisManager = redisManager;
|
||||
}
|
||||
|
||||
private static List<VideoKnowRes> 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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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<CourseGradingCriteria> criteriaDB;
|
||||
private readonly RedisManager redisManager;
|
||||
private readonly Repository<VideoTask> videoTaskDB;
|
||||
private readonly Repository<VideoKonwPoint> videoKonwPointDB;
|
||||
private readonly Repository<VideoQuestion> videoQuestionDB;
|
||||
|
|
@ -43,7 +43,9 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
|
|||
/// </summary>
|
||||
/// <param name="moonshotClient"></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, OssClient ossClient, Repository<VideoQuestionKonw> videoQuestionKonwDB)
|
||||
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, 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;
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取内容对应的章节
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 添加 SenseVoice 语音转文字
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
public static void AddSenseVoiceExpand(this IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton<SenseVoice>();
|
||||
}
|
||||
}
|
||||
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<VideoTask> videoTaskDB { get; set; }
|
||||
|
||||
private readonly RedisManager redisManager;
|
||||
|
||||
public SenseVoice(Repository<VideoTask> videoTaskDB, RedisManager redisManager)
|
||||
{
|
||||
this.videoTaskDB = videoTaskDB;
|
||||
this.redisManager = redisManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化 SenseVoice
|
||||
/// </summary>
|
||||
/// <param name="numThreads">默认6线程</param>
|
||||
/// <param name="useGPU">是否使用gpu 报错请看安装CUDA环境<see cref="https://k2-fsa.github.io/sherpa/onnx/pretrained_models/whisper/large-v3.html#run-with-gpu-float32"/></param>
|
||||
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
|
|||
/// </summary>
|
||||
/// <param name="s"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<List<SenseVoiceRes>> RunTask(Stream s)
|
||||
public async Task<List<SenseVoiceRes>> 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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取语音字幕
|
||||
/// </summary>
|
||||
/// <param name="task"></param>
|
||||
/// <returns></returns>
|
||||
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
|
|||
/// <param name="task">任务id [默认Null]</param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public static async Task<List<SenseVoiceRes>> TaskHandle(WaveReader reader, string? task = null)
|
||||
public async Task<List<SenseVoiceRes>> 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<VideoTask>()
|
||||
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
|
|||
/// <param name="VAD"></param>
|
||||
/// <param name="res">字幕处理后写入数组</param>
|
||||
/// <param name="totalSecond">总时长</param>
|
||||
/// <param name="task">所属任务id</param>
|
||||
/// <param name="progressCallback">任务回调</param>
|
||||
/// <returns></returns>
|
||||
public static async Task ReadNext(this VoiceActivityDetector VAD, List<SenseVoiceRes> res, float totalSecond, string? task = null)
|
||||
public async Task<double?> ReadNext(VoiceActivityDetector VAD, List<SenseVoiceRes> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<VideoTask>()
|
||||
.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();
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
/// <summary>
|
||||
/// 检测语言的方法
|
||||
|
|
|
|||
|
|
@ -93,14 +93,16 @@ namespace VideoAnalysisCore.Common
|
|||
private readonly Repository<VideoTask> videoTaskDB;
|
||||
private readonly Repository<NodePackageInfo> packageInfoTaskDB;
|
||||
private readonly Client vodClient;
|
||||
private readonly RedisManager redisManager;
|
||||
readonly string taskVideoName = "task.mp4";
|
||||
readonly string taskPPTVideoName = "ppt.mp4";
|
||||
|
||||
public DownloadFile(Repository<VideoTask> videoTaskDB, Client vodClient, Repository<NodePackageInfo> nackageInfoTaskDB)
|
||||
public DownloadFile(Repository<VideoTask> videoTaskDB, Client vodClient, Repository<NodePackageInfo> 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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
|||
/// </summary>
|
||||
public static class RedisExpandKey
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 基础key
|
||||
/// </summary>
|
||||
|
|
@ -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";
|
||||
/// <summary>
|
||||
/// 初始化 redis
|
||||
/// <para>需要在初始化配置文件时候调用</para>
|
||||
/// </summary>
|
||||
public static void AddTaskSubscribe(this IServiceCollection service)
|
||||
{
|
||||
|
||||
Console.WriteLine($"{DateTime.Now}=>初始化 Redis任务队列");
|
||||
service.AddSingleton<RedisInit>();
|
||||
}
|
||||
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<RedisManager>();
|
||||
}
|
||||
}
|
||||
|
||||
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<DownloadFile>() is null)
|
||||
throw new Exception("DownloadFile 未注入");
|
||||
else
|
||||
return scope.ServiceProvider.GetService<DownloadFile>()?.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<IBserGPT>() is null)
|
||||
throw new Exception("IBserGPT 未注入");
|
||||
else
|
||||
return scope.ServiceProvider.GetService<IBserGPT>()?.GetVideoType(task) ?? Task.CompletedTask;
|
||||
});
|
||||
SubscribeList.Add(RedisChannelEnum.AI模型分析, (task) =>
|
||||
{
|
||||
using var scope = AppCommon.Services?.CreateScope();
|
||||
if (scope is null || scope.ServiceProvider.GetService<IBserGPT>() is null)
|
||||
throw new Exception("IBserGPT 未注入");
|
||||
else
|
||||
return scope.ServiceProvider.GetService<IBserGPT>()?.GetKnow(task) ?? Task.CompletedTask;
|
||||
});
|
||||
SubscribeList.Add(RedisChannelEnum.AI分析试题, (task) =>
|
||||
{
|
||||
using var scope = AppCommon.Services?.CreateScope();
|
||||
if (scope is null || scope.ServiceProvider.GetService<IBserGPT>() is null)
|
||||
throw new Exception("IBserGPT 未注入");
|
||||
else
|
||||
return scope.ServiceProvider.GetService<IBserGPT>()?.GetVideoQuestion(task) ?? Task.CompletedTask;
|
||||
});
|
||||
SubscribeList.Add(RedisChannelEnum.结束任务, redisManager.TaskEnd);
|
||||
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// redis拓展
|
||||
/// </summary>
|
||||
public static class RedisExpand
|
||||
public class RedisManager
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// redis 连接
|
||||
/// </summary>
|
||||
public static RedisClient Redis = new RedisClient(AppCommon.Config.Redis.ConnectionString);
|
||||
public static bool StopTask { get; set; } = false;
|
||||
public static Dictionary<RedisChannelEnum, Func<string,Task>> SubscribeList = new Dictionary<RedisChannelEnum, Func<string, Task>>();
|
||||
/// <summary>
|
||||
/// 队列池
|
||||
/// </summary>
|
||||
static SubscribeListObject? Subscribe;
|
||||
public RedisClient Redis { get; set; }
|
||||
public Repository<VideoTask> videoTaskDB { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 初始化 redis
|
||||
/// <para>需要在初始化配置文件时候调用</para>
|
||||
/// </summary>
|
||||
public static void AddRedisExpand(this IServiceCollection service)
|
||||
public RedisManager(RedisClient redis, Repository<VideoTask> 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;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 缓存GPT任务缓存
|
||||
/// </summary>
|
||||
/// <param name="taskId"></param>
|
||||
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
|
|||
/// 加入到消费队列
|
||||
/// </summary>
|
||||
/// <param name="taskIds"></param>
|
||||
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
|
|||
/// 获取任务进度
|
||||
/// </summary>
|
||||
/// <param name="taskId"></param>
|
||||
public static float GetTaskProgress(object taskId)
|
||||
public float GetTaskProgress(object taskId)
|
||||
{
|
||||
return Redis.HMGet<float>(RedisExpandKey.Task(taskId), "Progress")[0];
|
||||
}
|
||||
|
|
@ -142,7 +210,7 @@ namespace VideoAnalysisCore.Common
|
|||
/// </summary>
|
||||
/// <param name="p">进度百分比</param>
|
||||
/// <param name="taskId"></param>
|
||||
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
|
|||
/// </summary>
|
||||
/// <param name="enum">枚举</param>
|
||||
/// <param name="taskId">任务id</param>
|
||||
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<VideoTask>()
|
||||
.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
|
|||
/// <summary>
|
||||
/// 初始化 队列 任务
|
||||
/// </summary>
|
||||
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<DownloadFile>() is null)
|
||||
throw new Exception("DownloadFile 未注入");
|
||||
else
|
||||
return scope.ServiceProvider.GetService<DownloadFile>()?.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<IBserGPT>() is null)
|
||||
throw new Exception("IBserGPT 未注入");
|
||||
else
|
||||
return scope.ServiceProvider.GetService<IBserGPT>()?.GetVideoType(task) ?? Task.CompletedTask;
|
||||
});
|
||||
SubscribeList.Add(RedisChannelEnum.AI模型分析, (task) =>
|
||||
{
|
||||
using var scope = AppCommon.Services?.CreateScope();
|
||||
if (scope is null || scope.ServiceProvider.GetService<IBserGPT>() is null)
|
||||
throw new Exception("IBserGPT 未注入");
|
||||
else
|
||||
return scope.ServiceProvider.GetService<IBserGPT>()?.GetKnow(task) ?? Task.CompletedTask;
|
||||
});
|
||||
SubscribeList.Add(RedisChannelEnum.AI分析试题, (task) =>
|
||||
{
|
||||
using var scope = AppCommon.Services?.CreateScope();
|
||||
if (scope is null || scope.ServiceProvider.GetService<IBserGPT>() is null)
|
||||
throw new Exception("IBserGPT 未注入");
|
||||
else
|
||||
return scope.ServiceProvider.GetService<IBserGPT>()?.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<RedisChannelEnum>(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;
|
||||
/// <summary>
|
||||
/// 停止接收新任务
|
||||
/// </summary>
|
||||
public static void StopTaskAsync()
|
||||
public void StopTaskAsync()
|
||||
{
|
||||
StopTask = true;
|
||||
try
|
||||
|
|
@ -297,7 +345,7 @@ namespace VideoAnalysisCore.Common
|
|||
/// <summary>
|
||||
/// 开始接收新任务
|
||||
/// </summary>
|
||||
public static void RestartTask()
|
||||
public void RestartTask()
|
||||
{
|
||||
StopTask = false;
|
||||
NewTask();
|
||||
|
|
@ -306,7 +354,7 @@ namespace VideoAnalysisCore.Common
|
|||
/// 重新执行新任务
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static void NewTask()
|
||||
public void NewTask()
|
||||
{
|
||||
// 取消 消费机的任务订阅
|
||||
if (StopTask)
|
||||
|
|
@ -320,7 +368,7 @@ namespace VideoAnalysisCore.Common
|
|||
/// <summary>
|
||||
/// 重新接收新任务
|
||||
/// </summary>
|
||||
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<RedisChannelEnum>(RedisExpandKey.Task(oldTask), "LastEnum")).FirstOrDefault();
|
||||
await InsertChannel(lastEnum, oldTask);
|
||||
return;
|
||||
}
|
||||
lock (Redis)
|
||||
{
|
||||
if (Subscribe?.IsUnsubscribed == false)//排除重试机制后 多次接收任务导致内存泄露
|
||||
|
|
@ -363,7 +402,7 @@ namespace VideoAnalysisCore.Common
|
|||
/// <param name="taskID"></param>
|
||||
/// <param name="ex"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<bool> SetTaskErrorMessage(long taskID, Exception? ex)
|
||||
public async Task<bool> SetTaskErrorMessage(long taskID, Exception? ex)
|
||||
{
|
||||
var error = string.Empty;
|
||||
if (ex != null)
|
||||
|
|
@ -386,17 +425,17 @@ namespace VideoAnalysisCore.Common
|
|||
/// </summary>
|
||||
/// <param name="taskID"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<bool> ClearTaskError(long taskID) =>await SetTaskError(taskID, string.Empty);
|
||||
public async Task<bool> ClearTaskError(long taskID) =>await SetTaskError(taskID, string.Empty);
|
||||
/// <summary>
|
||||
/// 修改任务的错误信息
|
||||
/// </summary>
|
||||
/// <param name="taskID"></param>
|
||||
/// <param name="error"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<bool> SetTaskError(long taskID, string? error)
|
||||
public async Task<bool> SetTaskError(long taskID, string? error)
|
||||
{
|
||||
Redis.HMSet(RedisExpandKey.Task(taskID), "ErrorMessage", error);
|
||||
return await DbScoped.Sugar.Updateable<VideoTask>()
|
||||
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
|
|||
/// <param name="key"></param>
|
||||
/// <param name="taskId"></param>
|
||||
/// <param name="action"></param>
|
||||
public static async Task TouchChannel(RedisChannelEnum key, string taskId, Func<string, Task> action = null)
|
||||
public async Task TouchChannel(RedisChannelEnum key, string taskId, Func<string, Task> 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<VideoTask>()
|
||||
videoTaskDB.AsUpdateable()
|
||||
.SetColumns(it => it.LastEnum == key)
|
||||
.Where(it => it.Id == tID)
|
||||
.ExecuteCommand();
|
||||
|
|
|
|||
|
|
@ -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<TenantAttribute>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,15 +28,19 @@ namespace VideoAnalysisCore.Controllers
|
|||
{
|
||||
private readonly IMapper mp;
|
||||
private readonly Repository<VideoTask> videoTaskDB;
|
||||
private readonly RedisManager redisManager;
|
||||
private readonly Repository<VideoKonwPoint> videoKonwDB;
|
||||
private readonly Repository<CourseInfo> courseInfoDB;
|
||||
public readonly SenseVoice senseVoice;
|
||||
public ApiController(Repository<VideoTask> videoTaskDB,
|
||||
IMapper mp, Repository<VideoKonwPoint> videoKonwDB, Repository<CourseInfo> courseInfoDB)
|
||||
IMapper mp, Repository<VideoKonwPoint> videoKonwDB, Repository<CourseInfo> 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();
|
||||
}
|
||||
/// <summary>
|
||||
|
|
@ -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<IActionResult> 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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,10 +38,11 @@ namespace VideoAnalysisCore.Controllers
|
|||
private readonly Repository<NodePackageInfo> nodePackageInfoDB;
|
||||
private readonly Repository<VideoQuestion> videoQuestionDB;
|
||||
private readonly Repository<VideoQuestionKonw> videoQuestionKonwDB;
|
||||
private readonly RedisManager redisManager;
|
||||
|
||||
public LJZK_Controller(IMapper mp, Repository<NodeSubscription> nodesubscriptionDB,
|
||||
Repository<VideoTask> videoTaskDB = null, Repository<VideoKonwPoint> videoKonwPointDB = null
|
||||
, Repository<NodePackageInfo> nodePackageInfoDB = null, Repository<VideoQuestion> videoQuestionDB = null, Repository<VideoQuestionKonw> videoQuestionKonwDB = null, Repository<CourseInfo> courseInfoDB = null)
|
||||
, Repository<NodePackageInfo> nodePackageInfoDB = null, Repository<VideoQuestion> videoQuestionDB = null, Repository<VideoQuestionKonw> videoQuestionKonwDB = null, Repository<CourseInfo> 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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<Attachments>($"""
|
||||
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<Attachments>($"""
|
||||
//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<VideoTask>(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<VideoTask>(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);
|
||||
|
||||
}
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue