Compare commits

..

No commits in common. "22e1a87a6876558029727289388535176da94e83" and "0de07e733a4edc7780bd742c7060ae242acf7eed" have entirely different histories.

19 changed files with 100 additions and 215 deletions

1
.gitignore vendored
View File

@ -369,4 +369,3 @@ VideoAnalysis/WebUI/node_modules/
VideoAnalysis/WebUI/dist/ VideoAnalysis/WebUI/dist/
VideoAnalysis/WebUI/.vscode/ VideoAnalysis/WebUI/.vscode/
/VideoAnalysis/device_id.config /VideoAnalysis/device_id.config
/Learn.VideoAnalysis.API/device_id.config

View File

@ -19,7 +19,6 @@ namespace Learn.VideoAnalysis.API.Expand
Console.WriteLine($"{DateTime.Now}=>初始化 Coravel"); Console.WriteLine($"{DateTime.Now}=>初始化 Coravel");
service.AddScheduler(); service.AddScheduler();
service.AddTransient<TaskFileClearJob>(); service.AddTransient<TaskFileClearJob>();
service.AddTransient<ClearAllCacheJob>();
service.AddTransient<NodePackageJob>(); service.AddTransient<NodePackageJob>();
} }

View File

@ -54,25 +54,10 @@ namespace Learn.VideoAnalysis.API.Expand
/// </summary> /// </summary>
/// <param name="context"></param> /// <param name="context"></param>
/// <exception cref="CustomException"></exception> /// <exception cref="CustomException"></exception>
public void ExecutingCached(ActionExecutingContext context) public void ExecutingFileCached(ActionExecutingContext context)
{ {
//特殊处理ResultIgnore不进行返回结果包装原样输出 //特殊处理ResultIgnore不进行返回结果包装原样输出
var endpoint = context.HttpContext.GetEndpoint(); var endpoint = context.HttpContext.GetEndpoint();
var request = context.HttpContext.Request;
// 1. 只有非 GET 请求且不是文件上传时才读取 Body
if (!request.Method.Equals("GET", StringComparison.OrdinalIgnoreCase)
&& !request.HasFormContentType)
{
// 确保从头开始读
request.Body.Position = 0;
// 使用 leaveOpen: true 防止 StreamReader 关闭底层的 Request.Body
using (var reader = new System.IO.StreamReader(request.Body, System.Text.Encoding.UTF8, detectEncodingFromByteOrderMarks: false, bufferSize: 1024, leaveOpen: true))
{
var body = reader.ReadToEnd();
context.HttpContext.Items["RequestBodyRaw"] = body;
request.Body.Position = 0;
}
}
// 直接返回原始结果,不封装 // 直接返回原始结果,不封装
if (endpoint?.Metadata.GetMetadata<HttpLogEnable>() == null) return; if (endpoint?.Metadata.GetMetadata<HttpLogEnable>() == null) return;
if (context.HttpContext.Request.HasFormContentType && if (context.HttpContext.Request.HasFormContentType &&
@ -89,8 +74,6 @@ namespace Learn.VideoAnalysis.API.Expand
}).ToArray(); }).ToArray();
} }
} }
/// <summary> /// <summary>
/// 执行接口前400 处理 /// 执行接口前400 处理
@ -166,19 +149,34 @@ namespace Learn.VideoAnalysis.API.Expand
/// <returns></returns> /// <returns></returns>
public async Task AddHttpLogAsync(HttpContext context, BaseReturn<object>? result = null, Exception? e = null) public async Task AddHttpLogAsync(HttpContext context, BaseReturn<object>? result = null, Exception? e = null)
{ {
//特殊处理ResultIgnore不进行返回结果包装原样输出
var endpoint = context.GetEndpoint();
// 所有请求都记录
//if (endpoint?.Metadata.GetMetadata<HttpLogEnable>() == null&& e is null) return;
string request = null; string request = null;
var logId = Yitter.IdGenerator.YitIdHelper.NextId(); var logId = Yitter.IdGenerator.YitIdHelper.NextId();
if (!context.Request.Method.Equals("GET", StringComparison.InvariantCultureIgnoreCase)) if (!context.Request.Method.Equals("GET", StringComparison.InvariantCultureIgnoreCase))
{
context.Request.EnableBuffering();
//记录请求参数
if (context.Request.Body.CanSeek)
{
try
{ {
var fileArr = context.Items.ContainsKey("FileCached") ? context.Items["FileCached"] as (IFormFile file, MemoryStream stream)[] : null; var fileArr = context.Items.ContainsKey("FileCached") ? context.Items["FileCached"] as (IFormFile file, MemoryStream stream)[] : null;
if (context.Request.HasFormContentType && fileArr != null) if (context.Request.HasFormContentType && fileArr != null)
{ {
// 设置保存目录例如项目根目录下的Uploads文件夹
string uploadsFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "UploadLogs", logId.ToString()); string uploadsFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "UploadLogs", logId.ToString());
// 创建目录(如果不存在)
if (!Directory.Exists(uploadsFolder)) if (!Directory.Exists(uploadsFolder))
Directory.CreateDirectory(uploadsFolder); Directory.CreateDirectory(uploadsFolder);
foreach (var fileInfo in fileArr) foreach (var fileInfo in fileArr)
{ {
// 生成安全文件名(防止路径遍历攻击)
string uniqueFileName = Guid.NewGuid().ToString().Substring(0, 5) + "_" + Path.GetFileName(fileInfo.file.FileName); string uniqueFileName = Guid.NewGuid().ToString().Substring(0, 5) + "_" + Path.GetFileName(fileInfo.file.FileName);
// 保存文件
using var stream = new FileStream(Path.Combine(uploadsFolder, uniqueFileName), FileMode.Create, FileAccess.Write); using var stream = new FileStream(Path.Combine(uploadsFolder, uniqueFileName), FileMode.Create, FileAccess.Write);
fileInfo.stream.Position = 0; fileInfo.stream.Position = 0;
await fileInfo.stream.CopyToAsync(stream); await fileInfo.stream.CopyToAsync(stream);
@ -186,11 +184,18 @@ namespace Learn.VideoAnalysis.API.Expand
} }
request = $"请求体包含{context.Request.Form.Files.Count()}个文件 目录 {uploadsFolder}"; request = $"请求体包含{context.Request.Form.Files.Count()}个文件 目录 {uploadsFolder}";
} }
else
}
if (context.Items.ContainsKey("RequestBodyRaw"))
{ {
request = context.Items["RequestBodyRaw"] as string; context.Request.Body.Position = 0;
using var sr = new System.IO.StreamReader(context.Request.Body);
request = await sr.ReadToEndAsync();
}
}
catch (Exception ex)
{
request = "处理请求入参时发生了错误 \r\n" + ex.ToString() + "\r\n 原有请求数据 " + request;
}
}
} }
//写入队列 //写入队列
await DbScoped.Sugar.CopyNew() await DbScoped.Sugar.CopyNew()
@ -200,7 +205,7 @@ namespace Learn.VideoAnalysis.API.Expand
Url = context.Request.Path + context.Request.QueryString, Url = context.Request.Path + context.Request.QueryString,
Method = context.Request.Method, Method = context.Request.Method,
Request = request, Request = request,
IP = GetClientIp(context), IP = $"{context.Connection?.RemoteIpAddress?.ToString()}",
ResponseCode = result?.Code ?? -1, ResponseCode = result?.Code ?? -1,
Response = (result != null ? JsonSerializer.Serialize(result) : null) , Response = (result != null ? JsonSerializer.Serialize(result) : null) ,
Authorization = context.Request.Headers.ContainsKey("Authorization") Authorization = context.Request.Headers.ContainsKey("Authorization")
@ -213,31 +218,21 @@ namespace Learn.VideoAnalysis.API.Expand
}).ExecuteCommandAsync(); }).ExecuteCommandAsync();
} }
private string GetClientIp(HttpContext context)
{
var headers = context.Request.Headers;
var ip = headers["X-Forwarded-For"].FirstOrDefault();
if (!string.IsNullOrWhiteSpace(ip))
{
ip = ip.Split(',', StringSplitOptions.RemoveEmptyEntries).FirstOrDefault()?.Trim();
}
if (string.IsNullOrWhiteSpace(ip))
{
ip = headers["X-Real-IP"].FirstOrDefault();
}
if (string.IsNullOrWhiteSpace(ip) && context.Connection.RemoteIpAddress != null)
{
ip = context.Connection.RemoteIpAddress.ToString();
}
return ip ?? string.Empty;
}
public override async void OnActionExecuting(ActionExecutingContext context) public override async void OnActionExecuting(ActionExecutingContext context)
{ {
// 过期的
//if (context.HttpContext.GetEndpoint()?
// .Metadata.GetMetadata<IAllowAnonymous>() is null)
//{
// context.Result = new UnauthorizedResult();
// return;
//}
Executing400(context); Executing400(context);
ExecutingCached(context); ExecutingFileCached(context);
base.OnActionExecuting(context);
} }
/// <summary> /// <summary>
@ -253,9 +248,6 @@ namespace Learn.VideoAnalysis.API.Expand
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine($"{DateTime.Now}=>接口规范出现异常");
Console.WriteLine(ex.Message);
Console.WriteLine(ex.StackTrace);
} }
base.OnActionExecuted(context); base.OnActionExecuted(context);

View File

@ -1,4 +1,4 @@
using Coravel; using Coravel;
using Coravel.Scheduling.Schedule; using Coravel.Scheduling.Schedule;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
@ -21,7 +21,6 @@ namespace Learn.VideoAnalysis.Expand
#if !DEBUG #if !DEBUG
service.AddTransient<TaskFileClearJob>(); service.AddTransient<TaskFileClearJob>();
#endif #endif
service.AddTransient<ClearAllCacheJob>();
service.AddTransient<NodePackageJob>(); service.AddTransient<NodePackageJob>();
} }
public static void UseCoravelExpand(this IApplicationBuilder provider) public static void UseCoravelExpand(this IApplicationBuilder provider)
@ -29,10 +28,8 @@ namespace Learn.VideoAnalysis.Expand
provider.ApplicationServices.UseScheduler(scheduler => provider.ApplicationServices.UseScheduler(scheduler =>
{ {
//任务缓存清理 //任务缓存清理
// scheduler.Schedule<TaskFileClearJob>().HourlyAt(10); scheduler.Schedule<TaskFileClearJob>().HourlyAt(10);
//强制清理所有缓存内容 //scheduler.Schedule<TaskFileClearJob>().DailyAt(1,0);
scheduler.Schedule<ClearAllCacheJob>().Hourly();
//scheduler.Schedule<ClearAllCacheJob>().EverySeconds(40);
}); });
} }
} }

View File

@ -106,6 +106,8 @@ namespace Learn.VideoAnalysis
AppCommon.Services = app.Services; AppCommon.Services = app.Services;
app.UseMiddleware<BasicAuthMiddleware>("Swagger"); app.UseMiddleware<BasicAuthMiddleware>("Swagger");
// Configure the HTTP request pipeline. // Configure the HTTP request pipeline.
//开启redis队列服务
_ = app.Services.GetRequiredService<RedisInit>();
app.UseSwagger(); app.UseSwagger();
app.UseSwaggerUI(); app.UseSwaggerUI();
app.UseExceptionHandler("/Error"); app.UseExceptionHandler("/Error");
@ -131,12 +133,7 @@ namespace Learn.VideoAnalysis
app.UseCorsExpand(); app.UseCorsExpand();
app.UseSqlSugarExpand(); app.UseSqlSugarExpand();
app.UseCoravelExpand(); app.UseCoravelExpand();
app.UseServiceSystem(() => app.UseServiceSystem();
{
//开启redis队列服务
_ = AppCommon.Services.GetRequiredService<RedisInit>();
});
app.Run(); app.Run();

View File

@ -52,7 +52,7 @@
"ChatGpt": { "ChatGpt": {
//"Host": "https://api.g4f.icu/", //"Host": "https://api.g4f.icu/",
"Host": "https://api.oaibest.com/", "Host": "https://api.oaibest.com/",
"ApiKey": "sk-uuCt3AZHawc9B543Yq5bxluO8aW35ArCY5fFnkh2LaJpFYA7", "ApiKey": "sk-D15tBln31N7dI9Fi7lds7OySFv5tOEK7DMNsG5rY2E6DCr4s",
"Path": "v1/chat/completions" "Path": "v1/chat/completions"
}, },
"DeepSeek": { "DeepSeek": {

View File

@ -14,10 +14,9 @@ namespace VideoAnalysisCore.AICore.GPT
public const string Deepseek_Reasoner = "deepseek-reasoner"; public const string Deepseek_Reasoner = "deepseek-reasoner";
public const string Deepseek_Chat = "deepseek-chat"; public const string Deepseek_Chat = "deepseek-chat";
//渠道限制没有并发
//public const string Gemini_3_Chat_thinking = "gemini-3-pro-preview-thinking"; public const string Gemini_3_Chat_thinking = "gemini-3-pro-preview-thinking";
public const string Gemini_3_Chat = "gemini-3-pro-preview"; public const string Gemini_3_Chat = "gemini-3-pro-preview";
public const string Gemini_3_Chat_flash = "gemini-3-flash-preview";
} }

View File

@ -1,4 +1,4 @@
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;

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;
@ -189,7 +189,8 @@ namespace VideoAnalysisCore.AICore.GPT
$"字幕列表 {rCaptionArr}。" + $"字幕列表 {rCaptionArr}。" +
$"输出格式 json字符串 对象格式{fileNameResFormat}"; $"输出格式 json字符串 对象格式{fileNameResFormat}";
var task = taskInfo.Id.ToString(); var task = taskInfo.Id.ToString();
var fileNameInfoRes = await geminiClient.ChatAsync<FileNameInfo>(task, fileNamePostMessages, "授课章节"); var fileNameInfoRes = await geminiClient.ChatAsync<FileNameInfo>
(task, fileNamePostMessages, "授课章节");
taskInfo.Sections = fileNameInfoRes.; taskInfo.Sections = fileNameInfoRes.;
await videoTaskDB.AsUpdateable() await videoTaskDB.AsUpdateable()
.SetColumns(it => it.Sections == fileNameInfoRes.) .SetColumns(it => it.Sections == fileNameInfoRes.)
@ -425,7 +426,7 @@ namespace VideoAnalysisCore.AICore.GPT
"""; """;
await redisManager.AddTaskLog(taskInfo.Id, $"开始分析视频内容 {tryCount}"); await redisManager.AddTaskLog(taskInfo.Id, $"开始分析视频内容 {tryCount}");
var res = await geminiClient.ChatAsync<List<VideoKnowRes>>(taskInfo.Id.ToString(), postMessages, "分析字幕", ChatGPTType.Gemini_3_Chat); var res = await geminiClient.ChatAsync<List<VideoKnowRes>>(taskInfo.Id.ToString(), postMessages, "分析字幕", ChatGPTType.Gemini_3_Chat_thinking);
return res; return res;
} }
catch (Exception ex) catch (Exception ex)
@ -568,8 +569,6 @@ namespace VideoAnalysisCore.AICore.GPT
/// <returns></returns> /// <returns></returns>
private async Task<SenseVoiceRes[]> AnalysisVideoQuestions(VideoTask taskInfo, List<KnowledgeInfo> knowledgeInfos) private async Task<SenseVoiceRes[]> AnalysisVideoQuestions(VideoTask taskInfo, List<KnowledgeInfo> knowledgeInfos)
{ {
await redisManager.AddTaskLog(taskInfo.Id, $"==>提取试题功能已禁用");
return null;
await redisManager.AddTaskLog(taskInfo.Id, $"==>{taskInfo.Id} 提取试题"); await redisManager.AddTaskLog(taskInfo.Id, $"==>{taskInfo.Id} 提取试题");
if (taskInfo is null || string.IsNullOrEmpty(taskInfo.PPTKeyFrame)) if (taskInfo is null || string.IsNullOrEmpty(taskInfo.PPTKeyFrame))
return null; return null;
@ -701,7 +700,6 @@ namespace VideoAnalysisCore.AICore.GPT
/// <returns></returns> /// <returns></returns>
public async Task<TaskRes> GetKnow(string task) public async Task<TaskRes> GetKnow(string task)
{ {
var taskId = long.Parse(task); var taskId = long.Parse(task);
var taskInfo = await videoTaskDB.AsQueryable() var taskInfo = await videoTaskDB.AsQueryable()
.Where(s => s.Id == taskId) .Where(s => s.Id == taskId)

View File

@ -46,7 +46,7 @@ namespace VideoAnalysisCore.AICore.GPT.Gemini
Message[] messageArr = [ Message[] messageArr = [
new Message(postMessages,"user"), new Message(postMessages,"user"),
]; ];
model = model ?? ChatGPTType.Gemini_3_Chat_flash; model = model ?? ChatGPTType.Gemini_3_Chat;
messageArr = messageArr.Where(s => s != null).ToArray(); messageArr = messageArr.Where(s => s != null).ToArray();
var chatReq = new ChatRequest var chatReq = new ChatRequest
{ {

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;
@ -49,7 +49,7 @@ namespace VideoAnalysisCore.AICore.SherpaOnnx
/// </summary> /// </summary>
public class SherpaVad public class SherpaVad
{ {
private VadModelConfig VADModelConfig; static VadModelConfig VADModelConfig = default!;
private readonly RedisManager redisManager; private readonly RedisManager redisManager;
private int WindowSize = 512; private int WindowSize = 512;
@ -137,7 +137,6 @@ namespace VideoAnalysisCore.AICore.SherpaOnnx
// 使用 Span 操作原始数据 // 使用 Span 操作原始数据
ReadOnlySpan<float> allSamples = reader.Samples.AsSpan(); ReadOnlySpan<float> allSamples = reader.Samples.AsSpan();
int numSamples = allSamples.Length; int numSamples = allSamples.Length;
VADModelConfig.SampleRate = reader.SampleRate;
int sampleRate = VADModelConfig.SampleRate; int sampleRate = VADModelConfig.SampleRate;
int numIter = numSamples / WindowSize; int numIter = numSamples / WindowSize;
var totalSecond = numSamples / (float)sampleRate; var totalSecond = numSamples / (float)sampleRate;

View File

@ -109,7 +109,7 @@ namespace VideoAnalysisCore.Common
public static string FrameName = "frame_"; public static string FrameName = "frame_";
/// <summary> /// <summary>
/// 删除 AI分析任务视频/PPT的缓存文件 /// 删除 AI分析任务的缓存文件
/// </summary> /// </summary>
/// <param name="taskId"></param> /// <param name="taskId"></param>
/// <returns></returns> /// <returns></returns>
@ -144,30 +144,6 @@ namespace VideoAnalysisCore.Common
return true; return true;
} }
/// <summary>
/// 删除 AI分析任务的缓存文件
/// </summary>
/// <param name="taskId"></param>
/// <returns></returns>
public static async Task<bool> DeleteTaskAllFileAsync(long? taskId, RedisManager redisManager)
{
if (taskId is null || taskId == 0) return false;
var path = taskId.ToString().LocalPath();
if (!string.IsNullOrEmpty(path) && Directory.Exists(path))
{
try
{
Directory.Delete(path, true);
await redisManager.AddTaskLog(taskId, $"已清理所有缓存文件: {taskId}");
}
catch (Exception ex)
{
await redisManager.AddTaskLog(taskId, $"删除缓存文件 {taskId} 时出错: {ex.Message}");
}
}
return true;
}
/// <summary> /// <summary>
/// 对象转化为JSON字符串 /// 对象转化为JSON字符串
/// </summary> /// </summary>

View File

@ -42,9 +42,7 @@ namespace VideoAnalysisCore.Common
context.Response.StatusCode = StatusCodes.Status401Unauthorized; context.Response.StatusCode = StatusCodes.Status401Unauthorized;
return; return;
} }
if (!context.Request.Method.Equals("GET", StringComparison.OrdinalIgnoreCase)
&& !context.Request.HasFormContentType)
context.Request.EnableBuffering();
await _next(context); await _next(context);
} }

View File

@ -1,4 +1,4 @@
using Downloader; using Downloader;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using SqlSugar; using SqlSugar;
using SqlSugar.IOC; using SqlSugar.IOC;
@ -94,17 +94,15 @@ namespace VideoAnalysisCore.Common
private readonly Repository<NodePackageInfo> packageInfoTaskDB; private readonly Repository<NodePackageInfo> packageInfoTaskDB;
private readonly Client vodClient; private readonly Client vodClient;
private readonly RedisManager redisManager; private readonly RedisManager redisManager;
private readonly IServiceProvider serviceProvider;
readonly string taskVideoName = "task.mp4"; readonly string taskVideoName = "task.mp4";
readonly string taskPPTVideoName = "ppt.mp4"; readonly string taskPPTVideoName = "ppt.mp4";
public DownloadFile(Repository<VideoTask> videoTaskDB, Client vodClient, Repository<NodePackageInfo> nackageInfoTaskDB, RedisManager redisManager, IServiceProvider serviceProvider) public DownloadFile(Repository<VideoTask> videoTaskDB, Client vodClient, Repository<NodePackageInfo> nackageInfoTaskDB, RedisManager redisManager)
{ {
this.videoTaskDB = videoTaskDB; this.videoTaskDB = videoTaskDB;
this.vodClient = vodClient; this.vodClient = vodClient;
this.packageInfoTaskDB = nackageInfoTaskDB; this.packageInfoTaskDB = nackageInfoTaskDB;
this.redisManager = redisManager; this.redisManager = redisManager;
this.serviceProvider = serviceProvider;
} }
// 根据 Content-Type 映射文件后缀 // 根据 Content-Type 映射文件后缀
@ -268,28 +266,9 @@ namespace VideoAnalysisCore.Common
download.DownloadFileCompleted += async (object? sender, AsyncCompletedEventArgs e) => download.DownloadFileCompleted += async (object? sender, AsyncCompletedEventArgs e) =>
{ {
if (download.Status == DownloadStatus.Failed && e.Error != null) if (download.Status == DownloadStatus.Failed && e.Error != null)
{
// 检查磁盘空间不足异常
if (e.Error.Message.Contains("not enough space on the disk", StringComparison.OrdinalIgnoreCase))
{
Console.WriteLine($"{DateTime.Now} 下载失败:磁盘空间不足。尝试清理缓存...");
try
{
using var scope = serviceProvider.CreateScope();
var clearJob = scope.ServiceProvider.GetRequiredService<TaskFileClearJob>();
await clearJob.Invoke();
}
catch (Exception ex)
{
Console.WriteLine($"清理缓存失败: {ex.Message}");
}
res.SetException(new Exception($"磁盘空间不足,下载失败。请手动清理盘符 {Path.GetPathRoot(localPath)}。详细错误:{e.Error.Message}"));
}
else
{ {
res.SetException(e.Error); res.SetException(e.Error);
} }
}
else if (download.Status == DownloadStatus.Completed) else if (download.Status == DownloadStatus.Completed)
{ {
res.SetResult(); res.SetResult();

View File

@ -24,7 +24,7 @@ namespace VideoAnalysisCore.Common.Expand
/// 系统服务 /// 系统服务
/// </summary> /// </summary>
/// <param name="app1"></param> /// <param name="app1"></param>
public static void UseServiceSystem(this IHost app1,Action? action=null) public static void UseServiceSystem(this IHost app1)
{ {
var app = app1.Services; var app = app1.Services;
// 注册启动后的回调 // 注册启动后的回调
@ -46,10 +46,7 @@ namespace VideoAnalysisCore.Common.Expand
.Replace("+", "127.0.0.1"); .Replace("+", "127.0.0.1");
var uri = new Uri(normalizedAddress); var uri = new Uri(normalizedAddress);
int port = uri.Port; // 这里的 port 就是你要的数字 (int) int port = uri.Port; // 这里的 port 就是你要的数字 (int)
if (OperatingSystem.IsWindows())
OpenBrowser($"http://localhost:{uri.Port}/ui/index.html"); OpenBrowser($"http://localhost:{uri.Port}/ui/index.html");
if(action != null)
action();
}); });
} }

View File

@ -414,9 +414,7 @@ namespace VideoAnalysisCore.Common
}).ExecuteCommandAsync(); }).ExecuteCommandAsync();
try try
{ {
//await ExpandFunction.DeleteTaskFileAsync(tId, this); await ExpandFunction.DeleteTaskFileAsync(tId, this);
await ExpandFunction.DeleteTaskAllFileAsync(tId, this);
} }
catch (Exception) catch (Exception)
{ {
@ -431,7 +429,6 @@ namespace VideoAnalysisCore.Common
/// </summary> /// </summary>
public async Task InitChannel() public async Task InitChannel()
{ {
Thread.Sleep(1000);
if (Redis is null) throw new Exception("redis未初始化"); if (Redis is null) throw new Exception("redis未初始化");
//处理之前程序结束前未能执行完的情况 //处理之前程序结束前未能执行完的情况
var oldTaskCount = Redis.LLen(RedisExpandKey.IDTask); var oldTaskCount = Redis.LLen(RedisExpandKey.IDTask);

View File

@ -13,6 +13,7 @@ namespace VideoAnalysisCore.Controllers
/// <summary> /// <summary>
/// 通用接口 /// 通用接口
/// </summary> /// </summary>
[Authorize(AuthenticationSchemes = Authentication.vdAdmin)]
[Route("api/[controller]")] [Route("api/[controller]")]
public class PublicController : ControllerBase public class PublicController : ControllerBase
{ {

View File

@ -1,57 +0,0 @@
using Coravel.Invocable;
using System;
using System.IO;
using System.Threading.Tasks;
using VideoAnalysisCore.Common;
namespace VideoAnalysisCore.Job
{
/// <summary>
/// 每小时强制清理缓存文件夹下所有内容的任务
/// </summary>
public class ClearAllCacheJob : IInvocable
{
public Task Invoke()
{
try
{
var cacheDir = AppCommon.TaskCachedFile;
if (!Directory.Exists(cacheDir))
{
return Task.CompletedTask;
}
Console.WriteLine($"{DateTime.Now} 开始强制清理缓存目录: {cacheDir}");
// 获取所有子目录
var directories = Directory.GetDirectories(cacheDir);
var i = 0;
foreach (var dir in directories)
{
try
{
// 检查文件夹创建时间如果是30分钟前的则删除防止删除正在运行的任务
if (Directory.GetCreationTime(dir) < DateTime.Now.AddMinutes(-30))
{
Directory.Delete(dir, true);
i++;
}
}
catch (Exception ex)
{
// 正在使用的文件夹会抛出异常,忽略即可
Console.WriteLine($"清理目录 {dir} 时发生错误 (可能正在使用): {ex.Message}");
}
}
Console.WriteLine($"已删除过期缓存数量 {i}");
}
catch (Exception ex)
{
Console.WriteLine($"强制清理缓存任务发生异常: {ex.Message}");
}
return Task.CompletedTask;
}
}
}

View File

@ -1,4 +1,4 @@
using AlibabaCloud.SDK.Vod20170321; using AlibabaCloud.SDK.Vod20170321;
using Coravel.Invocable; using Coravel.Invocable;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using System; using System;
@ -31,16 +31,16 @@ namespace VideoAnalysisCore.Job
this.videotaskDB = videotaskDB; this.videotaskDB = videotaskDB;
this.redisManager = redisManager; this.redisManager = redisManager;
} }
public async Task DeleteTaskAllCachesAsync() public void DeleteTaskAllCaches()
{ {
var startTime = 0; var startTime = -5;
var timeSpan = startTime - 999; var timeSpan = startTime - 999;
// 计算 {startTime} 天前已完成任务缓存 // 计算 6 天前已完成任务缓存
DateTime twoDaysAgo = DateTime.Now.AddDays(startTime); DateTime twoDaysAgo = DateTime.Now.AddDays(startTime);
DateTime endDaysAgo = DateTime.Now.AddDays(timeSpan); DateTime endDaysAgo = DateTime.Now.AddDays(timeSpan);
// 查询 {startTime} 天前任务执行完成的记录 // 查询 2 天前任务执行完成的记录
var completedTasks = videotaskDB.AsQueryable() var completedTasks = videotaskDB.AsQueryable()
.Where(t => ( .Where(t => (
//筛选 结束任务 或者 错误任务 //筛选 结束任务 或者 错误任务
@ -54,9 +54,23 @@ namespace VideoAnalysisCore.Job
// 遍历查询结果,删除缓存文件 // 遍历查询结果,删除缓存文件
foreach (var taskId in completedTasks) foreach (var taskId in completedTasks)
await ExpandFunction.DeleteTaskAllFileAsync(taskId, redisManager); {
var path = taskId.ToString().LocalPath();
if (!string.IsNullOrEmpty(path) && Directory.Exists(path))
{
try
{
Directory.Delete(path, true);
Console.WriteLine($"已删除缓存文件: {taskId}");
} }
public async Task DeleteTaskVideoCachesAsync() catch (Exception ex)
{
Console.WriteLine($"删除缓存文件 {taskId} 时出错: {ex.Message}");
}
}
}
}
public async void DeleteTaskVideoCaches()
{ {
try try
{ {
@ -90,8 +104,8 @@ namespace VideoAnalysisCore.Job
public async Task Invoke() public async Task Invoke()
{ {
Console.WriteLine($"{DateTime.Now} 执行=>{this.GetType().FullName}"); Console.WriteLine($"{DateTime.Now} 执行=>{this.GetType().FullName}");
await DeleteTaskVideoCachesAsync(); DeleteTaskVideoCaches();
await DeleteTaskAllCachesAsync(); DeleteTaskAllCaches();
} }
} }
} }