Compare commits

..

No commits in common. "3df0615dc43f0a17e8c8a05aaa3a0db6e92801e6" and "3b431b978a95680f20633e2422905ac0dd2ebd7f" have entirely different histories.

13 changed files with 131 additions and 166 deletions

View File

@ -61,20 +61,20 @@
"UpdateTable": false "UpdateTable": false
}, },
"AlibabaCloudVod": { "AlibabaCloudVod": {
"AccessKeyId": "LTAI5tFLXyC3ixVdxhxLih8K", "AccessKeyId": "LTAI5tDC6p9h747B7FHbgwkH",
"AccessKeySecret": "dlGu3WMoW0XQaoAYxiCPpnxry6qLhB", "AccessKeySecret": "vRKgmbp1LB05LaGOjh3ZrZxbHSLYLF",
"EndPoint": "vod.cn-shanghai.aliyuncs.com" // "EndPoint": "vod.cn-shanghai.aliyuncs.com" //
}, },
"AliyunOSS": { "AliyunOSS": {
"AccessKeyId": "LTAI5tFLXyC3ixVdxhxLih8K", "AccessKeyId": "LTAI5tDC6p9h747B7FHbgwkH",
"AccessKeySecret": "dlGu3WMoW0XQaoAYxiCPpnxry6qLhB", "AccessKeySecret": "vRKgmbp1LB05LaGOjh3ZrZxbHSLYLF",
"BucketDomain": "https://learn-videoanalysis.oss-cn-chengdu.aliyuncs.com", "BucketDomain": "https://learn-videoanalysis.oss-cn-chengdu.aliyuncs.com",
"Region": "cn-chengdu", "Region": "cn-chengdu",
"BucketName": "learn-videoanalysis", "BucketName": "learn-videoanalysis",
"EndPoint": "oss-cn-chengdu.aliyuncs.com" // "EndPoint": "oss-cn-chengdu.aliyuncs.com" //
}, },
"OtherDBArr": [ "OtherDBArr": [
{ // 线 {// 线
"ConfigId": 1001, //ResourceBank "ConfigId": 1001, //ResourceBank
"ConnectionString": "AllowLoadLocalInfile=true;Server=rm-2vc20nd3d11g0oh6g2o.rwlb.cn-chengdu.rds.aliyuncs.com;User ID=marking;Password=poiuytPOIUYT098765)(*&^%;Port=3306;Database=resourcebank;CharSet=utf8mb4;pooling=true;SslMode=None", "ConnectionString": "AllowLoadLocalInfile=true;Server=rm-2vc20nd3d11g0oh6g2o.rwlb.cn-chengdu.rds.aliyuncs.com;User ID=marking;Password=poiuytPOIUYT098765)(*&^%;Port=3306;Database=resourcebank;CharSet=utf8mb4;pooling=true;SslMode=None",
"SqlType": "MySql" "SqlType": "MySql"

View File

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

View File

@ -76,16 +76,16 @@
//"ConnectionString": "AllowLoadLocalInfile=true;Server=rm-2vc20nd3d11g0oh6g2o.rwlb.cn-chengdu.rds.aliyuncs.com;User ID=marking;Password=poiuytPOIUYT098765)(*&^%;Port=3306;Database=learn.videoanalysis;CharSet=utf8mb4;pooling=true;SslMode=None", //"ConnectionString": "AllowLoadLocalInfile=true;Server=rm-2vc20nd3d11g0oh6g2o.rwlb.cn-chengdu.rds.aliyuncs.com;User ID=marking;Password=poiuytPOIUYT098765)(*&^%;Port=3306;Database=learn.videoanalysis;CharSet=utf8mb4;pooling=true;SslMode=None",
"SqlType": "MySql", "SqlType": "MySql",
"UpdateTable": false "UpdateTable": true
}, },
"AlibabaCloudVod": { "AlibabaCloudVod": {
"AccessKeyId": "LTAI5tFLXyC3ixVdxhxLih8K", "AccessKeyId": "LTAI5tDC6p9h747B7FHbgwkH",
"AccessKeySecret": "dlGu3WMoW0XQaoAYxiCPpnxry6qLhB", "AccessKeySecret": "vRKgmbp1LB05LaGOjh3ZrZxbHSLYLF",
"EndPoint": "vod.cn-shanghai.aliyuncs.com" // "EndPoint": "vod.cn-shanghai.aliyuncs.com" //
}, },
"AliyunOSS": { "AliyunOSS": {
"AccessKeyId": "LTAI5tFLXyC3ixVdxhxLih8K", "AccessKeyId": "LTAI5tDC6p9h747B7FHbgwkH",
"AccessKeySecret": "dlGu3WMoW0XQaoAYxiCPpnxry6qLhB", "AccessKeySecret": "vRKgmbp1LB05LaGOjh3ZrZxbHSLYLF",
"BucketDomain": "https://learn-videoanalysis.oss-cn-chengdu.aliyuncs.com", "BucketDomain": "https://learn-videoanalysis.oss-cn-chengdu.aliyuncs.com",
"Region": "cn-chengdu", "Region": "cn-chengdu",
"BucketName": "learn-videoanalysis", "BucketName": "learn-videoanalysis",

View File

@ -16,7 +16,7 @@ using VideoAnalysisCore.AICore.GPT.Gemini;
namespace VideoAnalysisCore.AICore.GPT namespace VideoAnalysisCore.AICore.GPT
{ {
public interface IBaseGPTWorkflow public interface IBserGPTWorkflow
{ {
/// <summary> /// <summary>
/// 访问GPT /// 访问GPT
@ -185,13 +185,10 @@ namespace VideoAnalysisCore.AICore.GPT
public static void AddGPTService(this IServiceCollection services) public static void AddGPTService(this IServiceCollection services)
{ {
services.AddSingleton<DeepSeekGPTClient>(); services.AddSingleton<DeepSeekGPTClient>();
services.AddSingleton<BSET_DeepSeekGPTClient services.AddSingleton<BSET_DeepSeekGPTClient>();
>();
services.AddSingleton<BestAIClient>(); services.AddSingleton<BestAIClient>();
services.AddSingleton<GeminiGPTClient>(); services.AddSingleton<GeminiGPTClient>();
services.AddSingleton<IBaseGPTWorkflow, GTP_Analysis_1>(); services.AddSingleton<IBserGPTWorkflow, GTP_Analysis_1>();
} }

View File

@ -1,4 +1,4 @@
using VideoAnalysisCore.Common; using VideoAnalysisCore.Common;
using System.Text.Json; using System.Text.Json;
using VideoAnalysisCore.Model; using VideoAnalysisCore.Model;
using System.Text; using System.Text;
@ -33,7 +33,7 @@ namespace VideoAnalysisCore.AICore.GPT
/// <summary> /// <summary>
/// 视频分析工作流1 /// 视频分析工作流1
/// </summary> /// </summary>
public class GTP_Analysis_1 : IBaseGPTWorkflow public class GTP_Analysis_1 : IBserGPTWorkflow
{ {
private readonly GeminiGPTClient geminiClient; private readonly GeminiGPTClient geminiClient;
private readonly DeepSeekGPTClient deepSeekClient; private readonly DeepSeekGPTClient deepSeekClient;

View File

@ -1,4 +1,4 @@
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using SherpaOnnx; using SherpaOnnx;
using SqlSugar; using SqlSugar;

View File

@ -148,34 +148,21 @@ namespace VideoAnalysisCore.Common
public async Task RunTask(string task, string workflowName = "VideoSliceWorkflow") public async Task RunTask(string task, string workflowName = "VideoSliceWorkflow")
{ {
var taskId = long.Parse(task); var taskId = long.Parse(task);
var taskInfo = await GetTaskInfoAsync(taskId); //获取资源文件 地址
var fileUrl = await GetMediaUrlAsync(taskInfo);
// 准备本地目录
var localPath = task.LocalPath();
await PrepareDirectoryAndDbAsync(taskId, localPath);
// 处理 PPT 视频
await ProcessPPTVideoAsync(taskInfo, localPath, taskId, workflowName, task);
// 下载主视频
await DownloadWithCacheCheckAsync(taskId, fileUrl, localPath, taskVideoName, workflowName, task, "主视频");
}
private async Task<VideoTask> GetTaskInfoAsync(long taskId)
{
var taskInfo = await videoTaskDB.CopyNew().AsQueryable() var taskInfo = await videoTaskDB.CopyNew().AsQueryable()
.Where(s => s.Id == taskId).FirstAsync(); .Where(s => s.Id == taskId).FirstAsync();
if (taskInfo is null )
if (taskInfo is null)
throw new Exception($"任务为null/是教研视频/没有视频课程名称"); throw new Exception($"任务为null/是教研视频/没有视频课程名称");
return taskInfo;
}
private async Task<string> GetMediaUrlAsync(VideoTask taskInfo)
{
var fileUrl = taskInfo.MediaUrl; var fileUrl = taskInfo.MediaUrl;
switch (taskInfo?.VideoType)
{
case AttachmentsInfoType.:
case AttachmentsInfoType.:
case AttachmentsInfoType.:
break;
default:
throw new Exception("无效的课程类型");
}
if (string.IsNullOrEmpty(fileUrl)) if (string.IsNullOrEmpty(fileUrl))
{ {
var videoInfo = await vodClient.GetPlayInfoAsync(new GetPlayInfoRequest() var videoInfo = await vodClient.GetPlayInfoAsync(new GetPlayInfoRequest()
@ -189,70 +176,57 @@ namespace VideoAnalysisCore.Common
throw new Exception($"{DateTime.Now} 视频订阅=>获取阿里云视频信息失败 VideoCode {taskInfo.TagId} StatusCode {videoInfo?.StatusCode}"); throw new Exception($"{DateTime.Now} 视频订阅=>获取阿里云视频信息失败 VideoCode {taskInfo.TagId} StatusCode {videoInfo?.StatusCode}");
fileUrl = videoInfo.Body.PlayInfoList.PlayInfo.First().PlayURL; fileUrl = videoInfo.Body.PlayInfoList.PlayInfo.First().PlayURL;
} }
if (string.IsNullOrEmpty(fileUrl)) if (string.IsNullOrEmpty(fileUrl))
throw new Exception($"任务id[{taskInfo.Id}] 资源地址无效 {fileUrl}"); throw new Exception($"任务id[{task}] 资源地址无效 {fileUrl}");
// 尝试从 URL 中获取文件后缀 (保留原有校验逻辑) // 尝试从 URL 中获取文件后缀
string fileExtension = Path.GetExtension(new Uri(fileUrl).AbsolutePath); string fileExtension = Path.GetExtension(new Uri(fileUrl).AbsolutePath);
//否则 获取 从Content-Type 获取文件后缀
if (string.IsNullOrEmpty(fileExtension)) if (string.IsNullOrEmpty(fileExtension))
throw new Exception($"未能从资源路径中获取文件后缀"); throw new Exception($"未能从资源路径中获取文件后缀");
return fileUrl; //创建下载文件缓存路径
}
private async Task PrepareDirectoryAndDbAsync(long taskId, string localPath)
{
if (!Directory.Exists(AppCommon.TaskCachedFile)) Directory.CreateDirectory(AppCommon.TaskCachedFile); if (!Directory.Exists(AppCommon.TaskCachedFile)) Directory.CreateDirectory(AppCommon.TaskCachedFile);
var localPath = task.LocalPath();
var outputPath = Path.Combine(localPath, taskVideoName);
if (!Directory.Exists(localPath)) Directory.CreateDirectory(localPath); if (!Directory.Exists(localPath)) Directory.CreateDirectory(localPath);
var outputPath = Path.Combine(localPath, taskVideoName);
await videoTaskDB.CopyNew() await videoTaskDB.CopyNew()
.AsUpdateable() .AsUpdateable()
.SetColumns(it => it.LocalMediaPath == outputPath) .SetColumns(it => it.LocalMediaPath == outputPath)
.Where(it => it.Id == taskId) .Where(it => it.Id == long.Parse(task))
.ExecuteCommandAsync(); .ExecuteCommandAsync();
} //下载PPT视频
if (string.IsNullOrEmpty(taskInfo.PPTVideoUrl)&&
private async Task ProcessPPTVideoAsync(VideoTask taskInfo, string localPath, long taskId, string workflowName, string taskStr) !string.IsNullOrEmpty(taskInfo.PPTVideoCode))
{
// 更新 PPT 视频 URL
if (string.IsNullOrEmpty(taskInfo.PPTVideoUrl) && !string.IsNullOrEmpty(taskInfo.PPTVideoCode))
{ {
taskInfo.PPTVideoUrl = await packageInfoTaskDB.AsQueryable() taskInfo.PPTVideoUrl = await packageInfoTaskDB.AsQueryable()
.Where(s => s.VideoCode == taskInfo.PPTVideoCode) .Where(s => s.VideoCode == taskInfo.PPTVideoCode)
.Select(s => s.VideoUrl) .Select(s => s.VideoUrl)
.FirstAsync(); .FirstAsync();
if (!string.IsNullOrEmpty(taskInfo.PPTVideoUrl)) if (!string.IsNullOrEmpty(taskInfo.PPTVideoUrl))
{
await videoTaskDB.CopyNew().AsUpdateable(taskInfo) await videoTaskDB.CopyNew().AsUpdateable(taskInfo)
.UpdateColumns(it => new { it.PPTVideoUrl }) .UpdateColumns(it => new { it.PPTVideoUrl })
.ExecuteCommandAsync(); .ExecuteCommandAsync();
}
}
// 下载 PPT 视频 }
if (!string.IsNullOrEmpty(taskInfo.PPTVideoUrl)) if (!string.IsNullOrEmpty(taskInfo.PPTVideoUrl))
{ {
await DownloadWithCacheCheckAsync(taskId, taskInfo.PPTVideoUrl, localPath, taskPPTVideoName, workflowName, taskStr, "PPT视频", true); await Download(taskInfo.PPTVideoUrl, localPath, taskPPTVideoName,
(s, e) => GetWorkflowManager(workflowName).SetTaskProgress(task, "PPT->" + Math.Round(e.ProgressPercentage, 1))
);
} }
} try
private async Task DownloadWithCacheCheckAsync(long taskId, string url, string localPath, string fileName, string workflowName, string taskStr, string logPrefix, bool isPPT = false)
{
var filePath = Path.Combine(localPath, fileName);
if (File.Exists(filePath) && new FileInfo(filePath).Length > 10 * 1024 * 1024)
{ {
await GetWorkflowManager(workflowName).AddTaskLog(taskId, $"{logPrefix}命中本地缓存"); //下载原视频
await Download(fileUrl, localPath, taskVideoName,
(s, e) => GetWorkflowManager(workflowName).SetTaskProgress(task, Math.Round(e.ProgressPercentage, 1))
);
} }
else catch
{ {
await Download(url, localPath, fileName, (s, e) => throw;
{
var progressPrefix = isPPT ? "PPT->" : "";
GetWorkflowManager(workflowName).SetTaskProgress(taskStr, $"{progressPrefix}" + Math.Round(e.ProgressPercentage, 1));
});
} }
} }
@ -291,7 +265,7 @@ namespace VideoAnalysisCore.Common
try try
{ {
using var scope = serviceProvider.CreateScope(); using var scope = serviceProvider.CreateScope();
var clearJob = scope.ServiceProvider.GetRequiredService<ClearAllCacheJob>(); var clearJob = scope.ServiceProvider.GetRequiredService<TaskFileClearJob>();
await clearJob.Invoke(); await clearJob.Invoke();
} }
catch (Exception ex) catch (Exception ex)

View File

@ -1,4 +1,4 @@
using FreeRedis; using FreeRedis;
using FreeRedis.Internal; using FreeRedis.Internal;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
@ -140,13 +140,25 @@ namespace VideoAnalysisCore.Common
public class RedisManager public class RedisManager
{ {
public static bool StopTask { get; set; } = false; public static bool StopTask { get; set; } = false;
public static Dictionary<RedisChannelEnum, Func<string, Task>> SubscribeList = new Dictionary<RedisChannelEnum, Func<string, Task>>();
/// <summary>
/// 正在后台运行的任务集合
/// </summary>
public static ConcurrentDictionary<string, Task> RunningTasks = new ConcurrentDictionary<string, Task>();
private static CancellationTokenSource? _cts;
private static Task? _workerTask; private static Task? _workerTask;
public RedisClient Redis { get; set; } public RedisClient Redis { get; set; }
public Repository<VideoTask> videoTaskDB { get; set; }
public Repository<TaskLog> taskLogDB { get; set; }
public RedisManager(RedisClient redis) public RedisManager(RedisClient redis, Repository<VideoTask> videoTaskDB, Repository<TaskLog> taskLogDB)
{ {
Redis = redis; Redis = redis;
this.videoTaskDB = videoTaskDB;
this.taskLogDB = taskLogDB;
} }
@ -158,5 +170,37 @@ namespace VideoAnalysisCore.Common
{ {
Redis.Set(RedisExpandKey.TaskGPT(taskId) + ":" + time, data, timeoutSeconds: 3600 * 24); Redis.Set(RedisExpandKey.TaskGPT(taskId) + ":" + time, data, timeoutSeconds: 3600 * 24);
} }
/// <summary>
/// 加入到消费队列
/// </summary>
/// <param name="taskIds"></param>
public void JoinQueue(params long[] taskIds)
{ //事务
if (taskIds is null || taskIds.Length == 0)
return;
using (var tran = Redis.Multi())
{
foreach (var item in taskIds)
tran.LPush(RedisExpandKey.ChannelKey, item);
tran.Exec();
}
}
// AddTaskLog 已迁移至 WorkflowBase
/// <summary>
/// 获取任务进度
/// </summary>
/// <param name="taskId"></param>
/// <param name="workflowName">工作流名称(可选)</param>
public string GetTaskProgress(object taskId, string workflowName = "VideoSliceWorkflow")
{
var fieldName = workflowName == "VideoSliceWorkflow" ? "Progress" : $"Progress:{workflowName}";
return Redis.HMGet<string>(RedisExpandKey.Task(taskId), fieldName)[0] ?? "";
}
// 注意SetTaskProgress, TaskEnd, SetTaskErrorMessage, ClearTaskError, SetTaskError
// 已迁移至 WorkflowBase此处移除或标记为已废弃
} }
} }

View File

@ -39,15 +39,13 @@ namespace VideoAnalysisCore.Common
private readonly IServiceProvider _serviceProvider; private readonly IServiceProvider _serviceProvider;
private readonly FFMPGEHandle _ffmpeg; private readonly FFMPGEHandle _ffmpeg;
private readonly SenseVoice _senseVoice; private readonly SenseVoice _senseVoice;
private readonly TidySlideWorkflowManager _tidySlideWorkflowManager;
public VideoSliceWorkflowInit(VideoSliceWorkflowManager manager, IServiceProvider serviceProvider, FFMPGEHandle ffmpeg, SenseVoice senseVoice, TidySlideWorkflowManager tidySlideWorkflowManager) public VideoSliceWorkflowInit(VideoSliceWorkflowManager manager, IServiceProvider serviceProvider, FFMPGEHandle ffmpeg, SenseVoice senseVoice)
{ {
_manager = manager; _manager = manager;
_serviceProvider = serviceProvider; _serviceProvider = serviceProvider;
_ffmpeg = ffmpeg; _ffmpeg = ffmpeg;
_senseVoice = senseVoice; _senseVoice = senseVoice;
_tidySlideWorkflowManager = tidySlideWorkflowManager;
Init(); Init();
_manager.InitChannel(); _manager.InitChannel();
} }
@ -64,36 +62,26 @@ namespace VideoAnalysisCore.Common
await downloadService.RunTask(task, "VideoSliceWorkflow"); await downloadService.RunTask(task, "VideoSliceWorkflow");
}); });
SubscribeList.Add(RedisChannelEnum., _ffmpeg.RunAsync); SubscribeList.Add(RedisChannelEnum., _ffmpeg.RunAsync);
SubscribeList.Add(RedisChannelEnum., async (task) => SubscribeList.Add(RedisChannelEnum., _senseVoice.RunTask);
{
await _senseVoice.RunTask(task);
// 触发 TidySlide 工作流
if (AppCommon.Config.Workflow.TidySlide.Enabled)
{
await _tidySlideWorkflowManager.AddTaskLog(long.Parse(task), "由解析字幕完成触发 TidySlide 工作流");
//不阻塞
_=_tidySlideWorkflowManager.InsertChannel(RedisTidySlideChannelEnum., task);
}
});
SubscribeList.Add(RedisChannelEnum.AI课程类型, async (task) => SubscribeList.Add(RedisChannelEnum.AI课程类型, async (task) =>
{ {
using var scope = _serviceProvider.CreateScope(); using var scope = _serviceProvider.CreateScope();
var service = scope.ServiceProvider.GetService<IBaseGPTWorkflow>(); var service = scope.ServiceProvider.GetService<IBserGPTWorkflow>();
if (service is null) throw new Exception("IBserGPT 未注入"); if (service is null) throw new Exception("IBserGPT 未注入");
await service.GetVideoType(task); await service.GetVideoType(task);
}); });
SubscribeList.Add(RedisChannelEnum.AI模型分析, async (task) => SubscribeList.Add(RedisChannelEnum.AI模型分析, async (task) =>
{ {
using var scope = _serviceProvider.CreateScope(); using var scope = _serviceProvider.CreateScope();
var service = scope.ServiceProvider.GetService<IBaseGPTWorkflow>(); var service = scope.ServiceProvider.GetService<IBserGPTWorkflow>();
if (service is null) throw new Exception("IBserGPT 未注入"); if (service is null) throw new Exception("IBserGPT 未注入");
await service.GetKnow(task); await service.GetKnow(task);
}); });
SubscribeList.Add(RedisChannelEnum.AI分析试题, async (task) => SubscribeList.Add(RedisChannelEnum.AI分析试题, async (task) =>
{ {
using var scope = _serviceProvider.CreateScope(); using var scope = _serviceProvider.CreateScope();
var service = scope.ServiceProvider.GetService<IBaseGPTWorkflow>(); var service = scope.ServiceProvider.GetService<IBserGPTWorkflow>();
if (service is null) throw new Exception("IBserGPT 未注入"); if (service is null) throw new Exception("IBserGPT 未注入");
await service.GetVideoQuestion(task); await service.GetVideoQuestion(task);
}); });

View File

@ -461,19 +461,5 @@ namespace VideoAnalysisCore.Common
RunningTasks.TryAdd(tId, bgTask); RunningTasks.TryAdd(tId, bgTask);
await Task.CompletedTask; await Task.CompletedTask;
} }
/// <summary>
/// 加入到消费队列
/// </summary>
/// <param name="taskIds"></param>
public void JoinQueue(params long[] taskIds)
{
if (taskIds is null || taskIds.Length == 0)
return;
// 直接批量推入,避免循环和事务开销
var d = taskIds.Select(s => (object)s).ToArray();
Redis.LPush(ChannelKey, d);
}
} }
} }

View File

@ -39,12 +39,11 @@ namespace VideoAnalysisCore.Controllers
private readonly Repository<NodePackageInfo> nodePackageInfoDB; private readonly Repository<NodePackageInfo> nodePackageInfoDB;
private readonly Repository<VideoQuestion> videoQuestionDB; private readonly Repository<VideoQuestion> videoQuestionDB;
private readonly Repository<VideoQuestionKonw> videoQuestionKonwDB; private readonly Repository<VideoQuestionKonw> videoQuestionKonwDB;
private readonly RedisManager redisManager; private readonly RedisManager redisManager;
readonly VideoSliceWorkflowManager videoSliceWorkflowManager;
public LJZK_Controller(IMapper mp, Repository<NodeSubscription> nodesubscriptionDB, public LJZK_Controller(IMapper mp, Repository<NodeSubscription> nodesubscriptionDB,
Repository<VideoTask> videoTaskDB = null, Repository<VideoKonwPoint> videoKonwPointDB = null Repository<VideoTask> videoTaskDB = null, Repository<VideoKonwPoint> videoKonwPointDB = null
, Repository<NodePackageInfo> nodePackageInfoDB = null, Repository<VideoQuestion> videoQuestionDB = null, Repository<VideoQuestionKonw> videoQuestionKonwDB = null, Repository<CourseInfo> courseInfoDB = null, RedisManager redisManager = null, Repository<VideoTaskStage> videoTaskStageDB = null, VideoSliceWorkflowManager videoSliceWorkflowManager = null) , Repository<NodePackageInfo> nodePackageInfoDB = null, Repository<VideoQuestion> videoQuestionDB = null, Repository<VideoQuestionKonw> videoQuestionKonwDB = null, Repository<CourseInfo> courseInfoDB = null, RedisManager redisManager = null, Repository<VideoTaskStage> videoTaskStageDB = null)
{ {
this.mp = mp; this.mp = mp;
this.nodesubscriptionDB = nodesubscriptionDB; this.nodesubscriptionDB = nodesubscriptionDB;
@ -56,7 +55,6 @@ namespace VideoAnalysisCore.Controllers
this.courseInfoDB = courseInfoDB; this.courseInfoDB = courseInfoDB;
this.redisManager = redisManager; this.redisManager = redisManager;
this.videoTaskStageDB = videoTaskStageDB; this.videoTaskStageDB = videoTaskStageDB;
this.videoSliceWorkflowManager = videoSliceWorkflowManager;
} }
@ -160,7 +158,7 @@ namespace VideoAnalysisCore.Controllers
if (videos is null || videos.Count == 0) if (videos is null || videos.Count == 0)
return Ok(); return Ok();
var ids = videos.Select(s => s.Id).ToArray(); var ids = videos.Select(s => s.Id).ToArray();
videoSliceWorkflowManager.JoinQueue(ids); redisManager.JoinQueue(ids);
return Ok(); return Ok();
} }

View File

@ -110,30 +110,16 @@ namespace VideoAnalysisCore.Controllers
#endif #endif
/// <summary> /// <summary>
/// 添加任务到 TidySlide队列 /// 插入批量任务id
/// </summary> /// </summary>
/// <param name="ids">是否执行任务</param> /// <param name="ids">是否执行任务</param>
/// <returns></returns> /// <returns></returns>
[HttpPost(Name = "JoinQueueVideoSlice")] [HttpPost(Name = "JoinQueue")]
public IActionResult JoinQueue( long[] ids) public IActionResult JoinQueue(long[] ids)
{ {
if (ids == null || ids.Length == 0) if (ids == null || ids.Count() == 0)
return BadRequest("录入数据无效"); return BadRequest("录入数据无效");
videoSliceWorkflowManager.JoinQueue(ids); redisManager.JoinQueue(ids);
return Ok();
}
/// <summary>
/// 添加任务到 TidySlide队列
/// </summary>
/// <param name="ids"></param>
/// <returns></returns>
[HttpPost(Name = "JoinQueueTidySlide")]
public IActionResult JoinTidySlideQueue( long[] ids)
{
if (ids == null || ids.Length == 0)
return BadRequest("录入数据无效");
tidySlideWorkflowManager.JoinQueue(ids);
return Ok(); return Ok();
} }
@ -146,9 +132,9 @@ namespace VideoAnalysisCore.Controllers
public IActionResult StartTask(bool task) public IActionResult StartTask(bool task)
{ {
if (task) if (task)
videoSliceWorkflowManager.StopTask = false; videoSliceWorkflowManager.StopTask=false;
else else
videoSliceWorkflowManager.StopTask = true; videoSliceWorkflowManager.StopTask=true;
return Ok(); return Ok();
} }
/// <summary> /// <summary>
@ -182,7 +168,7 @@ namespace VideoAnalysisCore.Controllers
{ {
using var s = file.OpenReadStream(); using var s = file.OpenReadStream();
var res = senseVoice.RunTask(s); var res = senseVoice.RunTask(s);
return Ok(res); return Ok(res);
} }
/// <summary> /// <summary>
/// 语音识别 /// 语音识别
@ -262,7 +248,7 @@ namespace VideoAnalysisCore.Controllers
/// <param name="req">请求体</param> /// <param name="req">请求体</param>
/// <returns></returns> /// <returns></returns>
[HttpPost(Name = "VideoAnalysis_Batch")] [HttpPost(Name = "VideoAnalysis_Batch")]
public async Task<IActionResult> VideoAnalysis_Batch(VideoAnalysisReq[] req) public async Task<IActionResult> VideoAnalysis_Batch(VideoAnalysisReq[] req)
{ {
foreach (var item in req) foreach (var item in req)
await VideoAnalysis(item); await VideoAnalysis(item);
@ -385,8 +371,8 @@ namespace VideoAnalysisCore.Controllers
.LRangeAsync<TaskLog>(RedisExpandKey.TaskLog, 0, 99)) .LRangeAsync<TaskLog>(RedisExpandKey.TaskLog, 0, 99))
.Where(s => s.VideoTaskId == id); .Where(s => s.VideoTaskId == id);
logArr = logArr.Concat(insertData).ToArray(); logArr = logArr.Concat(insertData).ToArray();
// 获取所有相关工作流的状态 // 获取所有相关工作流的状态
var workflows = await baseService.Context.Queryable<VideoTaskWorkflow>() var workflows = await baseService.Context.Queryable<VideoTaskWorkflow>()
.Where(w => w.VideoTaskId == id) .Where(w => w.VideoTaskId == id)
@ -478,15 +464,7 @@ namespace VideoAnalysisCore.Controllers
{ {
// 扫描 Heartbeat Key // 扫描 Heartbeat Key
var pattern = RedisExpandKey.DeviceHeartbeat("*"); var pattern = RedisExpandKey.DeviceHeartbeat("*");
var keys = new List<string>(); var keys = redisManager.Redis.Scan(pattern, 1000).ToList();
long cursor = 0;
do
{
var scanResult = redisManager.Redis.Scan(cursor, pattern, 1000, null);
keys.AddRange(scanResult.items);
cursor = scanResult.cursor;
} while (cursor != 0);
var prefix = RedisExpandKey.DeviceHeartbeat(""); var prefix = RedisExpandKey.DeviceHeartbeat("");
var devices = keys.Select(k => k.Replace(prefix, "")).ToList(); var devices = keys.Select(k => k.Replace(prefix, "")).ToList();
return Ok(devices); return Ok(devices);
@ -512,15 +490,7 @@ namespace VideoAnalysisCore.Controllers
oldTaskArr = new List<long>(); oldTaskArr = new List<long>();
// 直接扫描 Heartbeat Key 获取在线设备 // 直接扫描 Heartbeat Key 获取在线设备
var pattern = RedisExpandKey.DeviceHeartbeat("*"); var pattern = RedisExpandKey.DeviceHeartbeat("*");
var keys = new List<string>(); var keys = redisManager.Redis.Scan(pattern, 1000).ToList();
long cursor = 0;
do
{
var scanResult = redisManager.Redis.Scan(cursor, pattern, 1000, null);
keys.AddRange(scanResult.items);
cursor = scanResult.cursor;
} while (cursor != 0);
var prefix = RedisExpandKey.DeviceHeartbeat(""); var prefix = RedisExpandKey.DeviceHeartbeat("");
var onlineDevices = keys.Select(k => k.Replace(prefix, "")).ToList(); var onlineDevices = keys.Select(k => k.Replace(prefix, "")).ToList();
@ -567,7 +537,7 @@ namespace VideoAnalysisCore.Controllers
public async Task<object> ErrorTaskList([FromBody] QueryRequestBase model) public async Task<object> ErrorTaskList([FromBody] QueryRequestBase model)
{ {
var sqlquery = base.BaseQuery(model) var sqlquery = base.BaseQuery(model)
.Where(s => s.ErrorMessage != null && s.ErrorMessage != "") .Where(s => s.ErrorMessage!=null && s.ErrorMessage !="")
.Select(s => new VideoTask .Select(s => new VideoTask
{ {
Id = s.Id, Id = s.Id,
@ -592,14 +562,14 @@ namespace VideoAnalysisCore.Controllers
/// <param name="id">查询模型</param> /// <param name="id">查询模型</param>
/// <returns></returns> /// <returns></returns>
[HttpGet] [HttpGet]
public async Task<IEnumerable<TaskLog>> TaskLog(long id) public async Task<IEnumerable<TaskLog>> TaskLog(long id )
{ {
var logArr = await taskLogDB.AsQueryable() var logArr = await taskLogDB.AsQueryable()
.Where(s => s.VideoTaskId == id) .Where(s => s.VideoTaskId == id)
.ToArrayAsync(); .ToArrayAsync();
var insertData = (await redisManager.Redis var insertData = (await redisManager.Redis
.LRangeAsync<TaskLog>(RedisExpandKey.TaskLog, 0, 99)) .LRangeAsync<TaskLog>(RedisExpandKey.TaskLog, 0, 99))
.Where(s => s.VideoTaskId == id); .Where(s=>s.VideoTaskId == id);
return logArr.Concat(insertData); return logArr.Concat(insertData);
} }
@ -616,10 +586,10 @@ namespace VideoAnalysisCore.Controllers
var result = await db.Queryable<TidySlideTaskResult>() var result = await db.Queryable<TidySlideTaskResult>()
.Where(s => s.VideoTaskId == id) .Where(s => s.VideoTaskId == id)
.FirstAsync(); .FirstAsync();
if (result == null) if (result == null)
return BadRequest("未找到 TidySlide 任务结果"); return BadRequest("未找到 TidySlide 任务结果");
return Ok(result); return Ok(result);
} }
} }

View File

@ -16,7 +16,7 @@
<PackageReference Include="AlibabaCloud.SDK.Vod20170321" Version="3.6.1" /> <PackageReference Include="AlibabaCloud.SDK.Vod20170321" Version="3.6.1" />
<PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.14.1" /> <PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.14.1" />
<PackageReference Include="Coravel" Version="6.0.2" /> <PackageReference Include="Coravel" Version="6.0.2" />
<PackageReference Include="FreeRedis" Version="1.5.5" /> <PackageReference Include="FreeRedis" Version="1.3.2" />
<PackageReference Include="Downloader" Version="3.2.1" /> <PackageReference Include="Downloader" Version="3.2.1" />
<PackageReference Include="Mapster" Version="7.4.1-pre01" /> <PackageReference Include="Mapster" Version="7.4.1-pre01" />
<PackageReference Include="Microsoft.AspNetCore.Cors" Version="2.3.0" /> <PackageReference Include="Microsoft.AspNetCore.Cors" Version="2.3.0" />