Compare commits
No commits in common. "3df0615dc43f0a17e8c8a05aaa3a0db6e92801e6" and "3b431b978a95680f20633e2422905ac0dd2ebd7f" have entirely different histories.
3df0615dc4
...
3b431b978a
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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>();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
{
|
||||||
|
//下载原视频
|
||||||
|
await Download(fileUrl, localPath, taskVideoName,
|
||||||
|
(s, e) => GetWorkflowManager(workflowName).SetTaskProgress(task, Math.Round(e.ProgressPercentage, 1))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
catch
|
||||||
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);
|
throw;
|
||||||
if (File.Exists(filePath) && new FileInfo(filePath).Length > 10 * 1024 * 1024)
|
|
||||||
{
|
|
||||||
await GetWorkflowManager(workflowName).AddTaskLog(taskId, $"{logPrefix}命中本地缓存");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await Download(url, localPath, fileName, (s, e) =>
|
|
||||||
{
|
|
||||||
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)
|
||||||
|
|
|
||||||
|
|
@ -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,此处移除或标记为已废弃
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,11 +40,10 @@ namespace VideoAnalysisCore.Controllers
|
||||||
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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" />
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue