拆分项目 为 API+消费端

修改 配置 定时任务 dockerFIle
This commit is contained in:
小肥羊 2025-04-08 18:16:32 +08:00
parent 972fba9959
commit 7ef238e4e2
49 changed files with 1384 additions and 159 deletions

View File

@ -0,0 +1,172 @@
{
"Env": [
{
"Name": "10楼刀片机",
"ServerList": [],
"LinuxServerList": [
{
"UserName": "heyang",
"Pwd": "9718CB3C9A0760CA326767D677ADEC1C",
"Host": "10.127.127.107",
"NickName": "10楼刀片机",
"IIsFireUrl": null,
"DockerFireUrl": "",
"WindowsServiceFireUrl": null,
"LinuxServiceFireUrl": null
}
],
"IgnoreList": [
"ffmpeg.exe"
],
"WindowsBackUpIgnoreList": []
},
{
"Name": "阿里云_代理",
"ServerList": [],
"LinuxServerList": [
{
"UserName": "heyang",
"Pwd": "AAC53130AF118B652BCED77C39B959F9",
"Host": "10.127.127.77:10022",
"NickName": "",
"IIsFireUrl": null,
"DockerFireUrl": "",
"WindowsServiceFireUrl": null,
"LinuxServiceFireUrl": null
}
],
"IgnoreList": [],
"WindowsBackUpIgnoreList": []
}
],
"IIsConfig": {
"SdkType": null,
"WebSiteName": "",
"LastEnvName": null,
"EnvPairList": [
{
"EnvName": "10楼刀片机",
"ConfigName": "",
"LinuxEnvParam": null,
"DockerPort": null,
"DockerEnvName": null,
"DockerVolume": null,
"DockerOther": null
},
{
"EnvName": "阿里云_代理",
"ConfigName": "",
"LinuxEnvParam": null,
"DockerPort": null,
"DockerEnvName": null,
"DockerVolume": null,
"DockerOther": null
}
]
},
"WindowsServiveConfig": {
"ServiceName": "",
"SdkType": null,
"LastEnvName": null,
"EnvPairList": [
{
"EnvName": "10楼刀片机",
"ConfigName": "",
"LinuxEnvParam": null,
"DockerPort": null,
"DockerEnvName": null,
"DockerVolume": null,
"DockerOther": null
},
{
"EnvName": "阿里云_代理",
"ConfigName": "",
"LinuxEnvParam": null,
"DockerPort": null,
"DockerEnvName": null,
"DockerVolume": null,
"DockerOther": null
}
]
},
"LinuxServiveConfig": {
"ServiceName": "",
"EnvParam": "",
"LastEnvName": null,
"EnvPairList": [
{
"EnvName": "10楼刀片机",
"ConfigName": "",
"LinuxEnvParam": null,
"DockerPort": null,
"DockerEnvName": null,
"DockerVolume": null,
"DockerOther": null
},
{
"EnvName": "阿里云_代理",
"ConfigName": "",
"LinuxEnvParam": null,
"DockerPort": null,
"DockerEnvName": null,
"DockerVolume": null,
"DockerOther": null
}
]
},
"DockerConfig": {
"Prot": "9040",
"AspNetCoreEnv": "",
"LastEnvName": "阿里云_代理",
"RemoveDaysFromPublished": "10",
"WorkDir": "/home/heyang/",
"Volume": "/home/hy/VideoAnalysis/AICore:/app/AICore/_Static;/home/hy/VideoAnalysis/TaskCachedFile:/app/TaskCachedFile",
"Other": "-e va_args=\"\" --name videoanalysis",
"EnvPairList": [
{
"EnvName": "10楼刀片机",
"ConfigName": null,
"LinuxEnvParam": null,
"DockerPort": "9040",
"DockerEnvName": "",
"DockerVolume": "/home/hy/VideoAnalysis/AICore:/app/AICore/_Static;/home/hy/VideoAnalysis/TaskCachedFile:/app/TaskCachedFile",
"DockerOther": "-e va_args=\"\""
},
{
"EnvName": "阿里云_代理",
"ConfigName": null,
"LinuxEnvParam": null,
"DockerPort": "9040",
"DockerEnvName": "",
"DockerVolume": "/home/hy/VideoAnalysis/AICore:/app/AICore/_Static;/home/hy/VideoAnalysis/TaskCachedFile:/app/TaskCachedFile",
"DockerOther": "-e va_args=\"\" --name videoanalysis"
}
]
},
"DockerImageConfig": {
"BaseHttpProxy": "",
"BaseImage": "",
"BaseImageCredential": {
"UserName": "",
"Password": ""
},
"TargetImage": "",
"TargetHttpProxy": "",
"TargetTags": [
""
],
"TargetImageCredential": {
"UserName": "",
"Password": ""
},
"ImageFormat": "Docker",
"Entrypoint": [
""
],
"Cmd": [
""
],
"IgnoreList": [],
"SkipExistingImages": false
}
}

View File

@ -0,0 +1,299 @@
using VideoAnalysisCore.Common;
using Microsoft.AspNetCore.Mvc;
using System.Reflection;
using MapsterMapper;
using Mapster;
using VideoAnalysisCore.AICore.SherpaOnnx;
using UserCenter.Model.Enum;
using VideoAnalysisCore.AICore.GPT.ChatGPT;
using VideoAnalysisCore.AICore.GPT;
using System.Text.Json;
using VideoAnalysisCore.Model.Enum;
using Yitter.IdGenerator;
using VideoAnalysisCore.Model;
using VideoAnalysisCore.Model.Dto;
using Learn.VideoAnalysis.API.Controllers.Dto;
namespace Learn.VideoAnalysis.API.Controllers
{
[ApiController]
[Route("[controller]/[action]")]
public class ApiController : ControllerBase
{
private readonly ILogger<ApiController> _logger;
private readonly IMapper mp;
private readonly Repository<VideoTask> videoTaskDB;
private readonly Repository<VideoKonwPoint> videoKonwDB;
private readonly IBserGPT chatGPT;
public ApiController(ILogger<ApiController> logger, Repository<VideoTask> videoTaskDB,
IMapper mp, IBserGPT chatGPT, Repository<VideoKonwPoint> videoKonwDB)
{
_logger = logger;
this.videoTaskDB = videoTaskDB;
this.mp = mp;
this.chatGPT = chatGPT;
this.videoKonwDB = videoKonwDB;
}
private string GetClientIpAddress()
{
// 检查 X-Forwarded-For 请求头
if (HttpContext.Request.Headers.ContainsKey("X-Forwarded-For")
&& !string.IsNullOrEmpty(HttpContext.Request.Headers["X-Forwarded-For"]))
return HttpContext.Request.Headers["X-Forwarded-For"].ToString();
if (HttpContext.Connection.RemoteIpAddress != null)
return HttpContext.Connection.RemoteIpAddress.ToString();
throw new Exception("未能获取到客户端ip地址");
}
/// <summary>
/// 语音识别
/// </summary>
/// <param name="url">文件流</param>
/// <returns></returns>
[HttpGet(Name = "AudioRecognitionUrl")]
public async Task<IActionResult> AudioRecognitionUrl(string url)
{
try
{
using HttpClient client = new HttpClient();
// 发送GET请求获取网络文件流
using var networkStream = await client.GetStreamAsync(url);
var res = await SenseVoice.RunTask(networkStream);
return Ok(res);
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
/// <summary>
/// 语音识别
/// </summary>
/// <param name="file">文件流</param>
/// <returns></returns>
[HttpPost(Name = "AudioRecognition")]
public async Task<IActionResult> AudioRecognition(IFormFile file)
{
using var s = file.OpenReadStream();
var res = await SenseVoice.RunTask(s);
return Ok(res);
}
/// <summary>
/// 获取FTS_Data str
/// </summary>
/// <param name="path">路径</param>
/// <returns></returns>
[HttpGet(Name = "fts_data")]
public async Task<IActionResult> FTS_Data(string path = "itn_subject_sx.fst")
{
var hotwords = JsonSerializer
.Deserialize<HotwordMode[]>(System.IO.File.ReadAllText(Path.Combine(AppCommon.AIModelFile, "Hotwords.json")));
var res = new List<string>(100);
foreach (var element in hotwords.OrderByDescending(s => s.key.Count()))
foreach (var e in element.v)
res.Add($"""("{e}", "{element.key}")""");
var pyFile = System.IO.File.ReadAllText(Path.Combine(AppCommon.AIModelFile, "sherpa-onnx-fst.py"));
var resStr = pyFile
.Replace("(fts_data)", "[" + string.Join(',', res) + "]")
.Replace("(path)", path);
return Ok(resStr);
}
/// <summary>
/// 重新开始执行GPT分析<para>taskId/tagId二选一</para>
/// </summary>
/// <param name="taskId"></param>
/// <param name="tagId">自定义id</param>
/// <param name="subject">切换任务所属学科 null忽略</param>
/// <returns></returns>
[HttpGet(Name = "ReStart")]
public async Task<IActionResult> ReStart(long taskId, string? tagId, SubjectEnum? subject)
{
var task = await videoTaskDB.AsQueryable()
.WhereIF(taskId != 0, s => s.Id == taskId)
.WhereIF(!string.IsNullOrEmpty(tagId), s => s.TagId == tagId)
.FirstAsync();
if (task is null)
return BadRequest("未能找到对应任务");
if (subject is not null)
{
task.Subject = subject;
await videoTaskDB.UpdateAsync(task);
}
//重新开始执行GPT分析
RedisExpand.InsertChannel(RedisChannelEnum.ChatModelAnalysis
, task.Id);
return Ok();
}
/// <summary>
/// 插入队列
/// </summary>
/// <param name="enum"></param>
/// <param name="msg"></param>
/// <returns></returns>
[HttpPost(Name = "TestInsertChannel")]
public IActionResult TestInsertChannel(int @enum = 1, string msg = "1")
{
RedisExpand.InsertChannel(@enum.ToEnum<RedisChannelEnum>().Value
, msg);
return Ok();
}
/// <summary>
/// 视频处理
/// </summary>
/// <param name="req">请求体</param>
/// <returns></returns>
[HttpPost(Name = "VideoAnalysis")]
public async Task<IActionResult> VideoAnalysis(VideoAnalysisReq req)
{
if (!ModelState.IsValid) return BadRequest(ModelState);
if (await videoTaskDB.IsAnyAsync(s => s.TagId == req.TagId))
return BadRequest("重复添加");
// 自动映射属性到哈希
var task = new VideoTask()
{
Id = YitIdHelper.NextId(),
ComeFrom = GetClientIpAddress(),
MediaUrl = req.MediaUrl,
ApiToken = req.ApiToken,
Type = req.Type,
Subject = req.Subject,
Tag = req.Tag,
TagId = req.TagId,
MediaName = req.Name
};
//入库
var hashEntries = task.GetType()
.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);
return Ok(task.Id);
}
///// <summary>
///// 获取视频知识点片段<para>taskId/tagId二选一</para>
///// </summary>
///// <param name="taskId"></param>
///// <param name="tagId">自定义id</param>
///// <returns></returns>
//[HttpGet(Name = "TaskKnowInfo")]
//public async Task<IActionResult> TaskKnowInfo(long taskId, string? tagId)
//{
// if (taskId == 0 && string.IsNullOrEmpty(tagId))
// return BadRequest();
// var task = await videoTaskDB.AsQueryable()
// .WhereIF(taskId != 0, s => s.Id == taskId)
// .WhereIF(!string.IsNullOrEmpty(tagId), s => s.TagId == tagId)
// .FirstAsync();
// if (task is null)
// return BadRequest("无效任务");
// var konwArr = await videoKonwDB.AsQueryable()
// .Where(s => s.VideoTaskId == task.Id)
// .ToArrayAsync();
// if (konwArr is null || konwArr.Length == 0)
// return BadRequest("无效任务");
// return Ok(new TaskKnowRes()
// {
// TagId = task.TagId,
// Status = task.LastEnum,
// VideoTaskId = task.Id,
// KnowBlockArr = konwArr
// .GroupBy(s => s.StartTime)
// .Select(s => new TaskKnowBlock()
// {
// Id = s.First().Id,
// Content = s.First().Content,
// StartTime = s.First().StartTime,
// EndTime = s.First().EndTime,
// Theme = s.First().Theme,
// Know = s.Select(x => new TaskKnowInfo()
// {
// Id = x.Id,
// KnowPoint = x.KnowPoint,
// KnowPointId = x.KnowPointId
// }).ToArray()
// }).ToArray()
// });
//}
///// <summary>
///// 获取视频信息<para>taskId/tagId二选一</para>
///// </summary>
///// <param name="taskId"></param>
///// <param name="tagId">自定义id</param>
///// <returns></returns>
//[HttpGet(Name = "TaskInfo")]
//public async Task<IActionResult> TaskInfo(long taskId, string? tagId)
//{
// if (taskId == 0 && string.IsNullOrEmpty(tagId))
// return BadRequest();
// var task = await videoTaskDB.AsQueryable()
// .WhereIF(taskId != 0, s => s.Id == taskId)
// .WhereIF(!string.IsNullOrEmpty(tagId), s => s.TagId == tagId)
// .FirstAsync();
// if (task is null)
// return BadRequest();
// var taskData = task.ChatAnalysis.Adapt<TaskInfoRes>();
// if (taskData is null)
// return BadRequest();
// taskData.Status = task.LastEnum;
// if (task.LastEnum != RedisChannelEnum.EndTask)
// return BadRequest(taskData);
// if (taskData != null && taskData.TimeBase != null)
// taskData.TimeBase = MergeTimeBases(taskData.TimeBase);
// return Ok(taskData);
//}
//[NonAction]
//private static List<TimeBase> MergeTimeBases(IEnumerable<TimeBase> timeBases)
//{
// if (timeBases == null || timeBases.Count() == 0)
// {
// return new List<TimeBase>();
// }
// var mergedList = new List<TimeBase>();
// // 初始化合并段
// var current = timeBases.First();
// current.Content = string.Empty;
// foreach (var next in timeBases)
// {
// // 如果类型相同,则扩展时间段
// if (current.TimeBaseType == next.TimeBaseType)
// current.End = Math.Max(current.End, next.End);
// else
// {
// // 类型不同,将当前时间段加入结果列表,并开始新时间段
// mergedList.Add(current);
// current = next;
// current.Content = string.Empty;
// }
// }
// // 添加最后的时间段
// mergedList.Add(current);
// return mergedList;
//}
}
}

View File

@ -0,0 +1,246 @@
using SqlSugar;
using System.ComponentModel.DataAnnotations;
using UserCenter.Model.Enum;
using VideoAnalysisCore.AICore.GPT.Dto;
using VideoAnalysisCore.Model.Enum;
namespace Learn.VideoAnalysis.API.Controllers.Dto
{
/// <summary>
/// 视频列表项
/// </summary>
public class StructurePageContentAnalyzeItem
{
/// <summary>
/// 录播内容编号
/// </summary>
public long StructurePageContentId { get; set; }
/// <summary>
/// 素材ID
/// </summary>
public long MaterialId { get; set; }
/// <summary>
/// 视频编码
/// </summary>
public string VideoCode { get; set; }
/// <summary>
/// 视频文件名称
/// </summary>
public string VideoName { get; set; }
/// <summary>
/// 内容类型
/// </summary>
public AttachmentsInfoType AttachmentsInfoType { get; set; }
}
public class NodePackageReq
{
/// <summary>
/// 录播结构目录节点编号
/// </summary>
[Required(ErrorMessage = "目录节点编号是必填项")]
public long NodeId { get; set; }
/// <summary>
/// 科目类型
/// </summary>
[Required(ErrorMessage = "科目类型是必填项")]
public SubjectEnum SubjectType { get; set; }
/// <summary>
/// 任务类型
/// </summary>
[Required(ErrorMessage = "任务类型是必填项")]
public TaskTypeEnum TaskType { get; set; }
/// <summary>
/// 视频列表
/// </summary>
[Required(ErrorMessage = "文件数量是必填项")]
public List<StructurePageContentAnalyzeItem> AnalyzeItems { get; set; }
}
/// <summary>
/// 视频处理 请求
/// </summary>
public class NodeMonitoringReq
{
/// <summary>
/// 媒体路径
/// </summary>
[Required(ErrorMessage = "文件节点ID是必填项")]
public long NodeId { get; set; }
/// <summary>
/// 任务类型
/// </summary>
public TaskTypeEnum? Type { get; set; }
/// <summary>
/// 学科类型
/// </summary>
public SubjectEnum? Subject { get; set; }
}
/// <summary>
/// 视频处理 请求
/// </summary>
public class VideoAnalysisReq
{
/// <summary>
/// 媒体路径
/// </summary>
[Required(ErrorMessage = "资源URL是必填项")]
public string MediaUrl { get; set; } = string.Empty;
/// <summary>
/// 资源名称
/// </summary>
[Required(ErrorMessage = "资源名称是必要的")]
public string Name { get; set; } = string.Empty;
/// <summary>
/// ApiKey
/// </summary>
[Required(ErrorMessage = "接口Token是必填项")]
public string ApiToken { get; set; } = string.Empty;
/// <summary>
/// 内容所属学科
/// </summary>
public SubjectEnum? Subject { get; set; }
/// <summary>
/// 任务类型
/// </summary>
public TaskTypeEnum? Type { get; set; }
/// <summary>
/// 自定义值 任务完成后附带通知
/// </summary>
public string Tag { get; set; } = string.Empty;
/// <summary>
/// 自定义Id可用于任务完成之后的查询
/// </summary>
public string? TagId { get; set; }
/// <summary>
///回调Api地址
/// </summary>
//[Required(ErrorMessage = "回调Api地址是必填项")]
//[Url(ErrorMessage = "请输入有效的 URL")]
//public string CallBackUrl { get; set; } = string.Empty;
}
public class TextValue
{
public TextValue(float v)
{
var s = TimeSpan.FromSeconds((double)v);
var td = new[] { s.Hours, s.Minutes, s.Seconds };
Text = string.Join(':', td.Where(s => s > 0));
Value = v;
}
public TextValue(string t, object v)
{
Text = t;
Value = v;
}
public TextValue()
{
}
public string Text { get; set; }
public object Value { get; set; }
}
public class TaskKnowInfo
{
/// <summary>
///视频片段知识点 id
/// </summary>
public long Id { get; set; }
/// <summary>
/// 知识点
/// </summary>
public string KnowPoint { get; set; }
/// <summary>
/// 知识点ID
/// </summary>
public string KnowPointId { get; set; }
}
public class TaskKnowBlock
{
public long Id { get; set; }
/// <summary>
/// 开始时间
/// </summary>
public float? StartTime { get; set; }
/// <summary>
/// 结束时间
/// </summary>
public float? EndTime { get; set; }
/// <summary>
/// 持续时间
/// </summary>
[SugarColumn(IsIgnore = true)]
public float? KeepTime => (EndTime ?? 0) - StartTime ?? 0;
/// <summary>
/// 主题
/// </summary>
public string? Theme { get; set; }
/// <summary>
/// 内容总结
/// </summary>
public string? Content { get; set; }
/// <summary>
/// 知识点列表
/// </summary>
public TaskKnowInfo[] Know { get; set; }
}
/// <summary>
/// 视频片段知识点结果
/// </summary>
public class TaskKnowRes
{
/// <summary>
/// 自定义Id [任务视频自定义id]
/// <see cref="VideoTask.TagId"/>
/// </summary>
public string? TagId { get; set; }
/// <summary>
/// 任务当前执行状态
/// </summary>
public RedisChannelEnum Status { get; set; }
/// <summary>
/// 视频任务id
/// </summary>
public long VideoTaskId { get; set; }
/// <summary>
/// 视频知识快
/// </summary>
public TaskKnowBlock[] KnowBlockArr { get; set; }
}
public class TaskInfoRes : TaskRes
{
public TaskInfoRes()
{
}
/// <summary>
/// 任务当前执行状态
/// </summary>
public RedisChannelEnum Status { get; set; }
///// <summary>
///// 时间轴状态枚举
///// </summary>
//public Dictionary<int, string> TimeTypeEnum =>
// Enum.GetValues(typeof(TimeBaseTypeEnum))
// .Cast<TimeBaseTypeEnum>()
// .ToDictionary(x => (int)x, x => x.ToString());
///// <summary>
///// 时间轴合计
///// </summary>
//public Dictionary<TimeBaseTypeEnum, TextValue>? TimeBaseTotal =>
// TimeBase?.GroupBy(s => s.TimeBaseType??TimeBaseTypeEnum.教师讲授)?
// .ToDictionary(s => s.Key, s => new TextValue(s.Sum(x => x.End - x.Start)));
}
}

View File

@ -0,0 +1,196 @@
using VideoAnalysisCore.Common;
using Microsoft.AspNetCore.Mvc;
using System.Reflection;
using MapsterMapper;
using Mapster;
using VideoAnalysisCore.AICore.SherpaOnnx;
using UserCenter.Model.Enum;
using VideoAnalysisCore.AICore.GPT.ChatGPT;
using VideoAnalysisCore.AICore.GPT;
using System.Text.Json;
using Microsoft.AspNetCore.Authorization;
using VideoAnalysisCore.Model.Enum;
using FFmpeg.NET.Services;
using Yitter.IdGenerator;
using VideoAnalysisCore.AICore.GPT.Dto;
using VideoAnalysisCore.Model;
using Learn.VideoAnalysis.API.Controllers.Dto;
namespace Learn.VideoAnalysis.API.Controllers
{
/// <summary>
/// 蓝鲸字库接口
/// </summary>
[ApiController]
[Route("LJZK/[action]")]
public class LJZK_Controller : ControllerBase
{
private readonly ILogger<LJZK_Controller> _logger;
private readonly IMapper mp;
private readonly Repository<NodeSubscription> nodesubscriptionDB;
private readonly Repository<VideoTask> videoTaskDB;
private readonly Repository<VideoKonwPoint> videoKonwPointDB;
private readonly Repository<NodePackageInfo> nodePackageInfoDB;
public LJZK_Controller(ILogger<LJZK_Controller> logger,
IMapper mp, Repository<NodeSubscription> nodesubscriptionDB,
Repository<VideoTask> videoTaskDB = null, Repository<VideoKonwPoint> videoKonwPointDB = null
, Repository<NodePackageInfo> nodePackageInfoDB = null)
{
_logger = logger;
this.mp = mp;
this.nodesubscriptionDB = nodesubscriptionDB;
this.videoTaskDB = videoTaskDB;
this.videoKonwPointDB = videoKonwPointDB;
this.nodePackageInfoDB = nodePackageInfoDB;
}
/// <summary>
/// 蓝鲸智库_添加文件节点监控
/// </summary>
/// <param name="req">请求体</param>
/// <returns></returns>
[HttpPost(Name = "NodeSubscription")]
public async Task<IActionResult> NodeSubscription(NodeMonitoringReq req)
{
if (req is null || req.NodeId == 0)
return BadRequest("无效的提交数据");
if (nodesubscriptionDB.IsAny(s => s.NodeId == req.NodeId))
return BadRequest("重复添加了节点监控任务" + req.NodeId);
var res = await nodesubscriptionDB.InsertReturnEntityAsync(new NodeSubscription()
{
NodeId = req.NodeId,
TaskType = req.Type ?? default,
Subject = req.Subject ?? default,
});
return Ok(res);
}
/// <summary>
/// 蓝鲸智库_文件包订阅
/// </summary>
/// <param name="req">请求体</param>
/// <returns></returns>
[HttpPost(Name = "NodePackage")]
public async Task<IActionResult> NodePackage(NodePackageReq req)
{
Console.WriteLine($"{DateTime.Now} 文件包订阅请求 req=" + JsonSerializer.Serialize(req));
if (req.AnalyzeItems is null || req.AnalyzeItems.Count() == 0)
return BadRequest("无效视频列表数据");
var videos = new List<VideoTask>(req.AnalyzeItems.Count);
var nodePackages = new List<NodePackageInfo>(req.AnalyzeItems.Count);
var videoIdArr = videoTaskDB.AsQueryable().Select(v => v.TagId).Distinct().ToArray();
foreach (var s in req.AnalyzeItems)
{
var np = new NodePackageInfo()
{
VideoCode = s.VideoCode,
AttachmentsInfoType = s.AttachmentsInfoType,
MaterialId = s.MaterialId,
StructurePageContentId = s.StructurePageContentId,
VideoName = s.VideoName,
NodeId = req.NodeId,
TaskType = req.TaskType,
SubjectType = req.SubjectType,
};
nodePackages.Add(np);
if (videoIdArr.Contains(s.VideoCode))
continue;
videos.Add(new VideoTask()
{
Id = YitIdHelper.NextId(),
ComeFrom = "127.0.0.1",
ApiToken = "",
Type = req.TaskType,
Subject = req.SubjectType,
TagId = s.VideoCode,
MediaUrl = string.Empty,
MediaName = s.VideoName
});
}
await nodePackageInfoDB.InsertRangeAsync(nodePackages);
await videoTaskDB.InsertRangeAsync(videos);
if (videos is null || videos.Count == 0)
return Ok();
var ids = videos.Select(s => s.Id).ToArray();
RedisExpand.JoinQueue(ids);
return Ok();
}
/// <summary>
/// 获取任务类型
/// </summary>
/// <returns></returns>
[HttpGet(Name = "TaskTypList")]
public IActionResult TaskType()
{
Type type = typeof(TaskTypeEnum);
return Ok(Enum.GetValues(type).Cast<object>()
.Select(s => new { Text = s.ToString(), Value = (int)s }));
}
/// <summary>
/// 获取学科类型
/// </summary>
/// <returns></returns>
[HttpGet(Name = "SubjectList")]
public IActionResult Subject()
{
Type type = typeof(SubjectEnum);
return Ok(Enum.GetValues(type).Cast<object>()
.Select(s => new { Text = s.ToString(), Value = (int)s }));
}
/// <summary>
/// 获取视频知识点片段<para>taskId/tagId二选一</para>
/// </summary>
/// <param name="taskId"></param>
/// <param name="tagId">自定义id</param>
/// <returns></returns>
[HttpGet(Name = "TaskKnowInfo")]
public async Task<IActionResult> TaskKnowInfo(long taskId, string? tagId)
{
if (taskId == 0 && string.IsNullOrEmpty(tagId))
return BadRequest();
var task = await videoTaskDB.AsQueryable()
.WhereIF(taskId != 0, s => s.Id == taskId)
.WhereIF(!string.IsNullOrEmpty(tagId), s => s.TagId == tagId)
.FirstAsync();
if (task is null)
return BadRequest("无效任务");
var konwArr = await videoKonwPointDB.AsQueryable()
.Where(s => s.VideoTaskId == task.Id)
.ToArrayAsync();
if (konwArr is null || konwArr.Length == 0)
return BadRequest("无效任务");
return Ok(new TaskKnowRes()
{
TagId = task.TagId,
Status = task.LastEnum,
VideoTaskId = task.Id,
KnowBlockArr = konwArr
.GroupBy(s => s.StartTime)
.Select(s => new TaskKnowBlock()
{
Id = s.First().Id,
Content = s.First().Content,
StartTime = s.First().StartTime,
EndTime = s.First().EndTime,
Theme = s.First().Theme,
Know = s.Select(x => new TaskKnowInfo()
{
Id = x.Id,
KnowPoint = x.KnowPoint,
KnowPointId = x.KnowPointId
}).ToArray()
}).ToArray()
});
}
}
}

View File

@ -0,0 +1,15 @@
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 9040
COPY . .
#设置时间为中国上海 环境为开发环境
ENV TZ=Asia/Shanghai
# 给我们要传的参数一个初始值
ENV va_args=
ENV ASPNETCORE_URLS=http://+:9040
ENTRYPOINT dotnet Learn.VideoAnalysis.API.dll $va_args

View File

@ -0,0 +1,36 @@
using Coravel;
using Coravel.Scheduling.Schedule;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VideoAnalysisCore.Job;
namespace Learn.VideoAnalysis.API.Expand
{
public static class CoravelExpand
{
public static void AddCoravel(this IServiceCollection service)
{
Console.WriteLine($"{DateTime.Now}=>初始化 Coravel");
service.AddScheduler();
service.AddTransient<NodeSubscriptionJob>();
service.AddTransient<TaskFileClearJob>();
service.AddTransient<NodePackageJob>();
}
public static void UseCoravelExpand(this IApplicationBuilder provider)
{
provider.ApplicationServices.UseScheduler(scheduler =>
{
//每5分钟执行一次 未处理视频扫描
scheduler.Schedule<NodeSubscriptionJob>().EveryFiveMinutes();
//文件包分析
scheduler.Schedule<NodePackageJob>().EveryThirtyMinutes(); //每30分钟执行一次
});
}
}
}

View File

@ -0,0 +1,41 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
</PropertyGroup>
<ItemGroup>
<None Remove="Dockerfile" />
</ItemGroup>
<ItemGroup>
<Content Include="Dockerfile">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Mapster.DependencyInjection" Version="1.0.2-pre01" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\VideoAnalysisCore\VideoAnalysisCore.csproj" />
</ItemGroup>
<ItemGroup>
<Content Update="AntDeploy.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="appsettings.Production.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>

View File

@ -0,0 +1,6 @@
@Learn.VideoAnalysis.API_HostAddress = http://localhost:5245
GET {{Learn.VideoAnalysis.API_HostAddress}}/weatherforecast/
Accept: application/json
###

View File

@ -0,0 +1,71 @@
using Learn.VideoAnalysis.API.Expand;
using Mapster;
using Microsoft.OpenApi.Models;
using VideoAnalysisCore.AICore.GPT.DeepSeek;
using VideoAnalysisCore.Common;
using VideoAnalysisCore.Common.Expand;
namespace Learn.VideoAnalysis.API
{
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c =>
{
var file = Path.Combine(AppContext.BaseDirectory, "Learn.VideoAnalysis.API.xml"); // xml文档绝对路径
c.IncludeXmlComments(file, true); // true : 显示控制器层注释
c.OrderActionsBy(o => o.RelativePath); // 对action的名称进行排序如果有多个就可以看见效果了。
});
builder.Services.AddMapster();
//初始化 插件
builder.Configuration.AddAppConfig(args);
builder.Services.AddSqlSugarExpand();
builder.Services.AddRedisExpand();
builder.Services.AddCoravel();
builder.Services.AddCorsExpand();
builder.Services.AddHttpContextAccessor();
builder.Services.AddControllersWithViews(options =>
{
options.Filters.Add(typeof(ExceptionFilter));
});
var app = builder.Build();
AppCommon.Services = app.Services;
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
//自定义 应用
app.UseCorsExpand();
app.UseSqlSugarExpand();
app.UseCoravelExpand();
app.Run();
}
}
}

View File

@ -0,0 +1,15 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"profiles": {
"http:5238": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:5238",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@ -0,0 +1,32 @@
{
"Logging": {
"LogLevel": {
"Default": "Error",
"Microsoft.AspNetCore": "Error"
}
},
"AppConfig": {
"TaskSetting": {
"DownloadSpeed": 8,
"IS_Server": true //?
},
"Subsystem": {
"蓝鲸智库": {
"APIUrl": "https://zyapi.23544.com",
"Token": ""
}
},
"Redis": {
"ConnectionString": "redis-external.23544.com:16379,password=poiuyt)(*&^%,defaultDatabase=3"
},
"FFmpeg": {
" TimeSlice": 600
},
"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=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",
"UpdateTable": false
}
}
}

View File

@ -0,0 +1,76 @@
{
"Logging": {
"LogLevel": {
"Default": "Warning",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"AppConfig": {
"ID": 1, //
"TaskSetting": {
"DownloadSpeed": 2,
"IS_Server": true //
},
"Admin": {
"Account": "admin",
"Password": "q1w2e3!@#"
},
"Subsystem": {
"蓝鲸智库": {
"APIUrl": "http://192.168.2.117:6400",
"Token": ""
}
},
"Redis": {
"ConnectionString": "127.0.0.1:6379,password=Woshiren123,defaultDatabase=10"
},
"Whisper": {
"ModelName": "ggml-small.bin"
},
"FFmpeg": {
" TimeSlice": 600
},
"ChatGpt": {
"KIMI": {
"Host": "https://api.moonshot.cn",
"ApiKey": "sk-8BvvhESZIkgUbiaaJhglPxFa4o2X9H3xEv9lXELrWWwGxHWY"
},
"ChatGpt": {
"Host": "https://api.g4f.icu/",
//"Host": "https://api.oaibest.com/",
"ApiKey": "sk-D15tBln31N7dI9Fi7lds7OySFv5tOEK7DMNsG5rY2E6DCr4s"
},
"DeepSeek": {
"Host": "https://api.deepseek.com/chat/completions",
"ApiKey": "sk-88d3d2bc3dae4d50854b2569b281cf76"
},
"aliyun": {
"Host": "https://dashscope.aliyuncs.com/compatible-mode/",
"ApiKey": "sk-1742c2bf7b9846ae835de598dc6c427b"
}
},
"DB": {
"ConnectionString": "AllowLoadLocalInfile=true;Server=192.168.2.9;User ID=root;Password=qwe123!@#;Port=3306;Database=learn.videoanalysis;CharSet=utf8mb4;pooling=true;SslMode=None",
"SqlType": "MySql",
"UpdateTable": false
},
"AlibabaCloudVod": {
"AccessKeyId": "LTAI5tDC6p9h747B7FHbgwkH",
"AccessKeySecret": "vRKgmbp1LB05LaGOjh3ZrZxbHSLYLF",
"EndPoint": "vod.cn-shanghai.aliyuncs.com" //
},
"OtherDBArr": [
{
"ConfigId": 1001, //ResourceBank
"ConnectionString": "Server=47.109.35.116;Database=ResourceBank;UID=live;Password=Woshiren^&*();MultipleActiveResultSets=true;Encrypt=True;TrustServerCertificate=True;",
"SqlType": "SqlServer"
},
{
"ConfigId": 1002, //App.public.live
"ConnectionString": "Server=47.109.35.116;Database=App.public.live;UID=live;Password=Woshiren^&*();MultipleActiveResultSets=true;Encrypt=True;TrustServerCertificate=True;",
"SqlType": "SqlServer"
}
]
}
}

View File

@ -7,6 +7,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Learn.VideoAnalysis", "Vide
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VideoAnalysisCore", "VideoAnalysisCore\VideoAnalysisCore.csproj", "{69F4243A-B22E-431B-8F0B-ECD8729B8665}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Learn.VideoAnalysis.API", "Learn.VideoAnalysis.API\Learn.VideoAnalysis.API.csproj", "{D31BA4AB-73FC-47B1-A10A-34FD5E921F4A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -21,6 +23,10 @@ Global
{69F4243A-B22E-431B-8F0B-ECD8729B8665}.Debug|Any CPU.Build.0 = Debug|Any CPU
{69F4243A-B22E-431B-8F0B-ECD8729B8665}.Release|Any CPU.ActiveCfg = Release|Any CPU
{69F4243A-B22E-431B-8F0B-ECD8729B8665}.Release|Any CPU.Build.0 = Release|Any CPU
{D31BA4AB-73FC-47B1-A10A-34FD5E921F4A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D31BA4AB-73FC-47B1-A10A-34FD5E921F4A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D31BA4AB-73FC-47B1-A10A-34FD5E921F4A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D31BA4AB-73FC-47B1-A10A-34FD5E921F4A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -5,7 +5,7 @@
"ServerList": [],
"LinuxServerList": [
{
"UserName": "hy",
"UserName": "heyang",
"Pwd": "9718CB3C9A0760CA326767D677ADEC1C",
"Host": "10.127.127.107",
"NickName": "10楼刀片机",
@ -117,11 +117,11 @@
"DockerConfig": {
"Prot": "9040",
"AspNetCoreEnv": "",
"LastEnvName": "阿里云_代理",
"LastEnvName": "10楼刀片机",
"RemoveDaysFromPublished": "10",
"WorkDir": "/home/heyang/",
"Volume": "/home/hy/VideoAnalysis/AICore:/app/AICore/_Static;/home/hy/VideoAnalysis/TaskCachedFile:/app/TaskCachedFile",
"Other": "-e va_args=\"NoTask\" --name videoanalysis",
"Other": "-e va_args=\"\"",
"EnvPairList": [
{
"EnvName": "10楼刀片机",
@ -130,7 +130,7 @@
"DockerPort": "9040",
"DockerEnvName": "",
"DockerVolume": "/home/hy/VideoAnalysis/AICore:/app/AICore/_Static;/home/hy/VideoAnalysis/TaskCachedFile:/app/TaskCachedFile",
"DockerOther": "-e va_args=\"NoTask1\""
"DockerOther": "-e va_args=\"\""
},
{
"EnvName": "阿里云_代理",
@ -139,7 +139,7 @@
"DockerPort": "9040",
"DockerEnvName": "",
"DockerVolume": "/home/hy/VideoAnalysis/AICore:/app/AICore/_Static;/home/hy/VideoAnalysis/TaskCachedFile:/app/TaskCachedFile",
"DockerOther": "-e va_args=\"NoTask\" --name videoanalysis"
"DockerOther": "-e va_args=\"IS_Server\" --name videoanalysis"
}
]
},

View File

@ -1,4 +1,5 @@
@namespace VideoAnalysisRazor.Layouts
@using static AntDesign.IconType
@inherits LayoutComponentBase
<AntDesign.ProLayout.BasicLayout

View File

@ -13,6 +13,7 @@ using UserCenter.Model.Enum;
using VideoAnalysisCore.Common;
using VideoAnalysisCore.Model.Enum;
using VideoAnalysisCore.Model;
using Learn.VideoAnalysis.API.Expand;
namespace Learn.VideoAnalysis.Components.Pages

View File

@ -13,6 +13,7 @@ using UserCenter.Model.Enum;
using VideoAnalysisCore.Common;
using VideoAnalysisCore.Model.Enum;
using VideoAnalysisCore.Model;
using Learn.VideoAnalysis.API.Expand;
namespace Learn.VideoAnalysis.Components.Pages

View File

@ -1,6 +1,7 @@
using AntDesign;
using AntDesign.TableModels;
using FFmpeg.NET.Services;
using Learn.VideoAnalysis.API.Expand;
using Learn.VideoAnalysis.Controllers.Dto;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;

View File

@ -16,6 +16,7 @@ using VideoAnalysisCore.Model.Enum;
using VideoAnalysisCore.Model;
using VideoAnalysisCore.Model.Dto;
using static System.Runtime.InteropServices.JavaScript.JSType;
using System.Text.Json;
namespace Learn.VideoAnalysis.Components.Pages
{
@ -29,6 +30,7 @@ namespace Learn.VideoAnalysis.Components.Pages
[Inject] private ConfirmService ComfirmService { get; set; } = default!;
[Inject] private IHttpContextAccessor HttpContext { get; set; } = default!;
[Inject] private Repository<VideoTask> taskDB { get; set; } = default!;
[Inject] private Repository<VideoKonwPoint> videoKonwPointDB { get; set; } = default!;
[Inject] private IJSRuntime JSRuntime { get; set; } = default!;
private VideoTask nowTask { get; set; } = default!;
@ -57,7 +59,7 @@ namespace Learn.VideoAnalysis.Components.Pages
}
public string getF(VideoKnowRes segment)
{
var sf = ((int)((segment.StartTime ?? 0) / 60)).ToString().PadLeft(2,'0');
var sf = ((int)((segment.StartTime ?? 0) / 60)).ToString().PadLeft(2, '0');
var sm = ((int)((segment.StartTime ?? 0) % 60)).ToString().PadLeft(2, '0');
return $"{sf}:{sm}";
//var ef = ((int)((segment.EndTime ?? 0) / 60)).ToString().PadLeft(2, '0');
@ -73,13 +75,27 @@ namespace Learn.VideoAnalysis.Components.Pages
return;
long taskId = this.taskId.Value;
nowTask = await taskDB.GetFirstAsync(s => s.Id == taskId);
if(nowTask is null)
if (nowTask is null)
return;
captionsArr = RedisExpand.Redis.HMGet<SenseVoiceRes[]>(RedisExpandKey.Task(taskId), "Captions").FirstOrDefault();
videoKnows = RedisExpand.Redis.HMGet<VideoKnowRes[]>(RedisExpandKey.Task(taskId), "VideoKnows").FirstOrDefault();
videoPath = AppCommon.GetVideoPath(nowTask.Id.ToString());
captionsArr = JsonSerializer.Deserialize<SenseVoiceRes[]>(nowTask.Captions);
RedisExpand.Redis.HMGet<SenseVoiceRes[]>(RedisExpandKey.Task(taskId), "Captions").FirstOrDefault();
await JSRuntime.InvokeVoidAsync("setDB", captionsArr,videoKnows, videoPath);
var konwArr = await videoKonwPointDB.AsQueryable()
.Where(s => s.VideoTaskId == nowTask.Id)
.ToArrayAsync();
videoKnows = konwArr
.GroupBy(s => s.StartTime)
.Select(s => new VideoKnowRes()
{
Content = s.First().Content,
StartTime = s.First().StartTime,
EndTime = s.First().EndTime,
Theme = s.First().Theme,
KnowPoint = string.Join(',', s.Select(x => x.KnowPoint))
}).ToArray();
videoPath = AppCommon.GetVideoPath(nowTask.Id.ToString());
await JSRuntime.InvokeVoidAsync("setDB", captionsArr, videoKnows, videoPath);
StateHasChanged();
}

View File

@ -51,7 +51,7 @@ namespace Learn.VideoAnalysis.Controllers.Dto
[Required(ErrorMessage = "科目类型是必填项")]
public SubjectEnum SubjectType { get; set; }
/// <summary>
/// <summary>
/// 任务类型
/// </summary>
[Required(ErrorMessage = "任务类型是必填项")]

View File

@ -1,6 +1,6 @@
#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
FROM harbor.w.23544.com:8843/marking/learnvideo-net8.0:v0.1 AS base
WORKDIR /app
@ -9,13 +9,9 @@ COPY . .
#设置时间为中国上海 环境为开发环境
ENV TZ=Asia/Shanghai
# 更新 apt 源
COPY sources.list /etc/apt/sources.list
RUN apt-get update
RUN apt-get install -y ffmpeg
# 给我们要传的参数一个初始值
ENV va_args=
ENV ASPNETCORE_URLS=http://+:9040

View File

@ -1,5 +1,6 @@
using Coravel;
using Coravel.Scheduling.Schedule;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
@ -12,7 +13,6 @@ namespace Learn.VideoAnalysis.Expand
{
public static class CoravelExpand
{
public static int MyProperty { get; set; }
public static void AddCoravel(this IServiceCollection service)
{
@ -22,15 +22,11 @@ namespace Learn.VideoAnalysis.Expand
service.AddTransient<TaskFileClearJob>();
service.AddTransient<NodePackageJob>();
}
public static void UseCoravelExpand(this IServiceProvider provider)
public static void UseCoravelExpand(this IApplicationBuilder provider)
{
provider.UseScheduler(scheduler =>
provider.ApplicationServices.UseScheduler(scheduler =>
{
//每5分钟执行一次 未处理视频扫描
scheduler.Schedule<NodeSubscriptionJob>().EveryFiveMinutes();
//文件包分析
scheduler.Schedule<NodePackageJob>().EveryThirtyMinutes(); //每30分钟执行一次
//任务缓存清理
//任务缓存清理
// scheduler.Schedule<TaskFileClearJob>().HourlyAt(10);
});
}

View File

@ -0,0 +1,48 @@
using SqlSugar;
using AntDesign;
using AntDesign.TableModels;
namespace Learn.VideoAnalysis.API.Expand
{
public static class SearchExpand
{
/// <summary>
/// 转换 ant 查询枚举 到 sqlsuger枚举
/// </summary>
/// <param name="filterOperator">ant 查询枚举</param>
/// <returns></returns>
/// <exception cref="ArgumentOutOfRangeException"></exception>
public static ConditionalType ConvertToConditionalType(TableFilterCompareOperator filterOperator)
{
return filterOperator switch
{
TableFilterCompareOperator.Equals => ConditionalType.Equal,
TableFilterCompareOperator.Contains => ConditionalType.Like,
TableFilterCompareOperator.StartsWith => ConditionalType.LikeLeft,
TableFilterCompareOperator.EndsWith => ConditionalType.LikeRight,
TableFilterCompareOperator.GreaterThan => ConditionalType.GreaterThan,
TableFilterCompareOperator.LessThan => ConditionalType.LessThan,
TableFilterCompareOperator.GreaterThanOrEquals => ConditionalType.GreaterThanOrEqual,
TableFilterCompareOperator.LessThanOrEquals => ConditionalType.LessThanOrEqual,
TableFilterCompareOperator.Condition => ConditionalType.In,
TableFilterCompareOperator.NotEquals => ConditionalType.NoEqual,
TableFilterCompareOperator.IsNull => ConditionalType.IsNullOrEmpty,
TableFilterCompareOperator.IsNotNull => ConditionalType.IsNot,
TableFilterCompareOperator.NotContains => ConditionalType.NoLike,
TableFilterCompareOperator.TheSameDateWith => ConditionalType.EqualNull,
TableFilterCompareOperator.Between => ConditionalType.Range,
_ => throw new ArgumentOutOfRangeException(nameof(filterOperator), filterOperator, "未知的枚举类型!")
};
}
public static List<IConditionalModel> ToSqlSugerWhere(this QueryModel qm)
{
return qm.FilterModel.SelectMany(s => s.Filters.Select(x => new ConditionalModel()
{
FieldName = s.FieldName,
ConditionalType = ConvertToConditionalType(x.FilterCompareOperator),
FieldValue = x.Value.GetType().IsEnum ? ((int)x.Value).ToString() : x.Value.ToString(),
} as IConditionalModel)).ToList();
}
}
}

View File

@ -32,10 +32,11 @@
<ItemGroup>
<ProjectReference Include="..\VideoAnalysisCore\VideoAnalysisCore.csproj" />
<PackageReference Include="AlibabaCloud.SDK.Vod20170321" Version="3.6.1" />
<PackageReference Include="AntDesign.ProLayout" Version="0.20.3" />
<PackageReference Include="Mapster.DependencyInjection" Version="1.0.2-pre01" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="8.0.5" />
<PackageReference Include="AntDesign.Extensions.Localization" Version="0.20.2.1" />
<PackageReference Include="AntDesign.Extensions.Localization" Version="0.20.3" />
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="8.0.0" />
<PackageReference Include="System.Net.Http.Json" Version="8.0.0" />

View File

@ -1,7 +1,6 @@
using VideoAnalysisCore.Common;
using Learn.VideoAnalysis.Components;
using Microsoft.OpenApi.Models;
using AntDesign.ProLayout;
using VideoAnalysisCore.AICore.SherpaOnnx;
using Mapster;
using VideoAnalysisCore.AICore.GPT;
@ -10,6 +9,7 @@ using VideoAnalysisCore.AICore.GPT.ChatGPT;
using Microsoft.Extensions.FileProviders;
using VideoAnalysisCore.AICore.GPT.DeepSeek;
using Microsoft.Extensions.DependencyInjection;
using VideoAnalysisCore.Common.Expand;
using Learn.VideoAnalysis.Expand;
@ -88,9 +88,6 @@ namespace Learn.VideoAnalysis
builder.Services.AddMapster();
builder.Services.AddCorsExpand();
builder.Services.Configure<ProSettings>(builder.Configuration.GetSection("ProSettings"));
builder.Services.AddHttpClient();
builder.Services.AddHttpContextAccessor();
builder.Services.AddSingleton<ChatGPTClient>();
@ -128,11 +125,11 @@ namespace Learn.VideoAnalysis
app.MapControllers();
app.UseCorsExpand();
//×Ô¶¨Òå Ó¦ÓÃ
SqlSugarExpand.InitDB();
app.Services.UseCoravelExpand();
app.UseCorsExpand();
app.UseSqlSugarExpand();
app.UseCoravelExpand();
app.Run();

View File

@ -8,7 +8,7 @@
"AppConfig": {
"TaskSetting": {
"DownloadSpeed": 8,
"ProcessingTasks": true //?
"IS_Server": false //?
},
"Subsystem": {
"蓝鲸智库": {
@ -17,7 +17,7 @@
}
},
"Redis": {
"ConnectionString": "172.28.0.1,password=qwe123!@#,defaultDatabase=3"
"ConnectionString": "redis-external.23544.com:16379,password=poiuyt)(*&^%,defaultDatabase=3"
},
"FFmpeg": {
" TimeSlice": 600

View File

@ -10,7 +10,7 @@
"ID": 1, //
"TaskSetting": {
"DownloadSpeed": 2,
"ProcessingTasks": true,//?
"IS_Server": false //
},
"Admin": {
"Account": "admin",

View File

@ -6,8 +6,6 @@ using Newtonsoft.Json.Linq;
using System.Net.Http;
using Newtonsoft.Json;
using System.Net.Http.Json;
using AntDesign;
using OneOf.Types;
using System.Net;

View File

@ -6,8 +6,6 @@ using Newtonsoft.Json.Linq;
using System.Net.Http;
using Newtonsoft.Json;
using System.Net.Http.Json;
using AntDesign;
using OneOf.Types;
using System.Net;
using VideoAnalysisCore.AICore.GPT.KIMI;
using System.Threading;

View File

@ -112,18 +112,6 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
VideoKnowRes[] questionRes;
while (true)
{
// var postMessages =
//$"你的任务是分析视频字幕内容并提取出中国高考考试试题方法点,然后分析出<知识块>,来帮助学生快速了解视频字幕的内容" +
//$"通过阅读并理解字幕内容.然后识别出{subject}学科中属于{fileNameInfoRes.授课章节}章节相关的方法点以及对应的时间段。" +
//$"关联合并知识内容相似的知识点来合并为<知识块>。" +
//$"分配空余未使用的时间段到内容相近的<知识块>时间区间来获取更加详细的上下文,但是请避免<知识块>之间时间重合。" +
//$"从提取出的<知识块>内容称来匹配我提供的知识点,来作为片段的知识点(请确保匹配的知识点是用户提供的,否则片段知识点值为空字符串)。" +
//$"提供的方法点名称({knows})。 格式 (方法点Id|方法点名称) 如果一个<知识块>出现多个知识点那么知识点Id与知识点名称都用逗号','分割。" +
//$"这是输入的视频字幕并且是包含时间戳的视频字幕的固定格式文本。" +
////$"字幕格式(说话人:开始秒:结束秒:内容|下一段字幕).以下是包含时间的视频字幕文本。字幕列表 {captions.Captions}。" +
//$"字幕格式(开始秒:结束秒:内容|下一段字幕).以下是包含时间的视频字幕文本。字幕列表 {captions.Captions}。" +
//$"最后请检查某些<知识块>之间的过渡是否自然,如果<知识块>时长超过500秒则考虑拆封为两个更加贴切的<知识块>.或者<知识块>时长小于30秒则考虑合并<知识块>到相邻的<知识块>)。" +
//$"输出内容只返回json格式({resFormat})";
var resFormat = """[{"StartTime":开始秒(number),"Theme":主题(string),"Content":内容总结(string)}]""";
var postMessages =

View File

@ -11,7 +11,6 @@ using System.ComponentModel.DataAnnotations;
using System.Reflection;
using FreeRedis;
using VideoAnalysisCore.Model.Dto;
using AntDesign;
using SqlSugar.IOC;
using VideoAnalysisCore.AICore.GPT.Dto;
using VideoAnalysisCore.AICore.GPT;

View File

@ -6,8 +6,6 @@ using Newtonsoft.Json.Linq;
using System.Net.Http;
using Newtonsoft.Json;
using System.Net.Http.Json;
using AntDesign;
using OneOf.Types;
using System.Net;
using Azure;
using System.Reflection.PortableExecutable;

View File

@ -1,6 +1,4 @@
using AntDesign;
using AntDesign.TableModels;
using FreeRedis;
using FreeRedis;
using Microsoft.Extensions.DependencyModel;
using SqlSugar;
using SqlSugar.IOC;
@ -155,43 +153,6 @@ namespace VideoAnalysisCore.Common
);
}
/// <summary>
/// 转换 ant 查询枚举 到 sqlsuger枚举
/// </summary>
/// <param name="filterOperator">ant 查询枚举</param>
/// <returns></returns>
/// <exception cref="ArgumentOutOfRangeException"></exception>
public static ConditionalType ConvertToConditionalType(TableFilterCompareOperator filterOperator)
{
return filterOperator switch
{
TableFilterCompareOperator.Equals => ConditionalType.Equal,
TableFilterCompareOperator.Contains => ConditionalType.Like,
TableFilterCompareOperator.StartsWith => ConditionalType.LikeLeft,
TableFilterCompareOperator.EndsWith => ConditionalType.LikeRight,
TableFilterCompareOperator.GreaterThan => ConditionalType.GreaterThan,
TableFilterCompareOperator.LessThan => ConditionalType.LessThan,
TableFilterCompareOperator.GreaterThanOrEquals => ConditionalType.GreaterThanOrEqual,
TableFilterCompareOperator.LessThanOrEquals => ConditionalType.LessThanOrEqual,
TableFilterCompareOperator.Condition => ConditionalType.In,
TableFilterCompareOperator.NotEquals => ConditionalType.NoEqual,
TableFilterCompareOperator.IsNull => ConditionalType.IsNullOrEmpty,
TableFilterCompareOperator.IsNotNull => ConditionalType.IsNot,
TableFilterCompareOperator.NotContains => ConditionalType.NoLike,
TableFilterCompareOperator.TheSameDateWith => ConditionalType.EqualNull,
TableFilterCompareOperator.Between => ConditionalType.Range,
_ => throw new ArgumentOutOfRangeException(nameof(filterOperator), filterOperator, "未知的枚举类型!")
};
}
public static List<IConditionalModel> ToSqlSugerWhere(this QueryModel qm )
{
return qm.FilterModel.SelectMany(s => s.Filters.Select(x => new ConditionalModel()
{
FieldName = s.FieldName,
ConditionalType = ConvertToConditionalType( x.FilterCompareOperator),
FieldValue = x.Value.GetType().IsEnum?((int)x.Value).ToString() : x.Value.ToString(),
} as IConditionalModel)).ToList();
}
/// <summary>
/// 获取应用有效程序集
/// </summary>
/// <returns>IEnumerable</returns>

View File

@ -66,11 +66,12 @@ namespace VideoAnalysisCore.Common
/// <summary>
/// 下载速度MB/S
/// </summary>
public int DownloadSpeed { get; set; }
public int DownloadSpeed { get; set; }
/// <summary>
/// 是否接收任务
/// 是服务端
/// <para>不执行任务,不回调接口</para>
/// </summary>
public bool ProcessingTasks { get; set; }
public bool IS_Server { get; set; }
}
/// <summary>

View File

@ -1,5 +1,4 @@
using AntDesign;
using Downloader;
using Downloader;
using Microsoft.Extensions.DependencyInjection;
using SqlSugar;
using SqlSugar.IOC;

View File

@ -1,5 +1,4 @@
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Collections.Generic;
@ -20,23 +19,21 @@ namespace VideoAnalysisCore.Common
public async Task OnExceptionAsync(ExceptionContext context)
{
// 创建一个包含错误信息的对象
var errorObject = new
{
// 创建一个包含错误信息的对象
var errorObject = new
{
ErrorMessage = context.Exception.Message,
StackTrace = context.Exception.StackTrace,
};
// 将错误对象序列化为JSON格式
var json = JsonSerializer.Serialize(errorObject);
ErrorMessage = context.Exception.Message,
StackTrace = context.Exception.StackTrace,
};
// 将错误对象序列化为JSON格式
var json = JsonSerializer.Serialize(errorObject);
// 设置响应内容类型为JSON
context.HttpContext.Response.ContentType = "application/json";
// 设置状态码
context.HttpContext.Response.StatusCode = 500;
// 将JSON数据写入响应体
await context.HttpContext.Response.WriteAsync(json);
}
// 设置响应内容类型为JSON
context.HttpContext.Response.ContentType = "application/json";
// 设置状态码
context.HttpContext.Response.StatusCode = 500;
// 将JSON数据写入响应体
await context.HttpContext.Response.WriteAsync(json);
}
}
}

View File

@ -1,17 +1,18 @@
using Coravel;
using Microsoft.Extensions.Configuration;
using System.Collections.Generic;
using VideoAnalysisCore.Common;
using VideoAnalysisCore.Job;
namespace Learn.VideoAnalysis.Expand
namespace VideoAnalysisCore.Common.Expand
{
public static class AppConfigExpand
{
public static void AddAppConfig(this ConfigurationManager cm, string[] args)
public static void AddAppConfig(this IConfigurationManager cm, string[] args)
{
Console.WriteLine($"{DateTime.Now}=>初始化 AppConfig");
cm.GetSection("AppConfig").Bind(AppCommon.Config);
var argList= args.ToList();
var argList = args.ToList();
var eArgs = Environment.GetEnvironmentVariable("va_args");
if (!string.IsNullOrEmpty(eArgs))
argList.AddRange(eArgs.Split(","));
@ -21,8 +22,8 @@ namespace Learn.VideoAnalysis.Expand
Console.WriteLine(string.Join(',', args));
Console.WriteLine("===========================================");
if (args.Contains("NoTask"))
AppCommon.Config.TaskSetting.ProcessingTasks = false;
if (args.Contains("IS_Server"))
AppCommon.Config.TaskSetting.IS_Server = true;
}
}
}

View File

@ -1,10 +1,10 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
namespace Learn.VideoAnalysis.Expand
namespace VideoAnalysisCore.Common.Expand
{
/// <summary>
///
/// 跨域
/// </summary>
public static class CorsExpand
{
@ -14,7 +14,7 @@ namespace Learn.VideoAnalysis.Expand
/// <param name="services"></param>
public static void AddCorsExpand(this IServiceCollection services)
{
services.AddCors(c =>
CorsServiceCollectionExtensions.AddCors(services,c =>
{
c.AddPolicy("All", policy =>
{
@ -26,7 +26,7 @@ namespace Learn.VideoAnalysis.Expand
/// 使用跨域
/// </summary>
/// <param name="app"></param>
public static void UseCorsExpand(this WebApplication app)
public static void UseCorsExpand(this IApplicationBuilder app)
{
app.UseCors("All");
// 获取配置文件中的允许跨域的地址

View File

@ -1,4 +1,5 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using MySqlConnector;
using SqlSugar;
@ -13,7 +14,7 @@ using System.Xml.Linq;
using VideoAnalysisCore.Common;
using Yitter.IdGenerator;
namespace Learn.VideoAnalysis.Expand
namespace VideoAnalysisCore.Common.Expand
{
public static class SqlSugarExpand
{
@ -21,7 +22,7 @@ namespace Learn.VideoAnalysis.Expand
public static void AddSqlSugarExpand(this IServiceCollection services)
{
services.AddHttpContextAccessor();
HttpServiceCollectionExtensions.AddHttpContextAccessor(services);
Console.WriteLine($"{DateTime.Now}=>初始化 YitId雪花ID");
var options = new IdGeneratorOptions(ushort.Parse(AppCommon.Config.ID));
YitIdHelper.SetIdGenerator(options);
@ -102,7 +103,7 @@ namespace Learn.VideoAnalysis.Expand
#endregion
}
public static void InitDB()
public static void UseSqlSugarExpand(this IApplicationBuilder app)
{
ShowSQL = false;
var builder = new MySqlConnectionStringBuilder(AppCommon.Config.DB.ConnectionString);

View File

@ -0,0 +1,15 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VideoAnalysisCore.Common.Expand
{
public static class StartUpExpand
{
}
}

View File

@ -1,5 +1,4 @@
using AntDesign;
using FreeRedis;
using FreeRedis;
using FreeRedis.Internal;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json.Schema;
@ -276,8 +275,11 @@ namespace VideoAnalysisCore.Common
/// </summary>
public static async Task ReceivingTaskAsync()
{
if (!AppCommon.Config.TaskSetting.ProcessingTasks)//是否接收任务
if (AppCommon.Config.TaskSetting.IS_Server)
{
Console.WriteLine($"{DateTime.Now} =>服务端不接收任务");
return;
}
var oldTask = await Redis.GetAsync(RedisExpandKey.IDTask);
if (!string.IsNullOrEmpty(oldTask))
{

View File

@ -40,11 +40,10 @@ namespace VideoAnalysisCore.Job
}
public async Task Invoke()
{
Console.WriteLine($"{DateTime.Now} Invoke=>文件包任务");
Console.WriteLine($"{DateTime.Now} 执行=>文件包任务");
var taskArr = await nodePackageInfoDB.AsQueryable()
.Where(s => s.SuccessTime == null)
.ToArrayAsync();
.Where(s => s.SuccessTime == null)
.ToArrayAsync();
var videoIdArr = await videoTaskDB.AsQueryable()
.Where(s => s.EndTime != null)
.Select(s => s.TagId)
@ -58,7 +57,7 @@ namespace VideoAnalysisCore.Job
item.SuccessTime = DateTime.Now;
}
}
Console.WriteLine($"{DateTime.Now} Invoke=>文件包任务 已完成任务回调 数量{postData.Count}");
Console.WriteLine($"{DateTime.Now} 执行=>文件包任务 已完成任务回调 数量{postData.Count}");
if (postData.Count() == 0)
return;
var responseMessage = await new HttpClient()
@ -66,16 +65,16 @@ namespace VideoAnalysisCore.Job
if (responseMessage.IsSuccessStatusCode)
{
var res = await responseMessage.Content.ReadAsStringAsync();
Console.WriteLine($"{DateTime.Now} Invoke=>文件包任务 回调结果 {res}");
Console.WriteLine($"{DateTime.Now} 执行=>文件包任务 回调结果 {res}");
await nodePackageInfoDB.AsUpdateable(postData)
.UpdateColumns(it => new { it.SuccessTime })
.ExecuteCommandAsync();
}
else
else
{
var res = await responseMessage.Content.ReadAsStringAsync();
Console.WriteLine($"{DateTime.Now} Invoke=>文件包任务 回调失败!!! {responseMessage.StatusCode} {res}");
Console.WriteLine($"{DateTime.Now} 执行=>文件包任务 回调失败!!! {responseMessage.StatusCode} {res}");
}
}
}

View File

@ -35,7 +35,8 @@ namespace VideoAnalysisCore.Job
}
public async Task Invoke()
{
Console.WriteLine($"{DateTime.Now} Invoke=>{this.GetType().FullName}");
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.);

View File

@ -71,7 +71,7 @@ namespace VideoAnalysisCore.Job
}
public async Task Invoke()
{
Console.WriteLine($"{DateTime.Now} Invoke=>{this.GetType().FullName}");
Console.WriteLine($"{DateTime.Now} 执行=>{this.GetType().FullName}");
DeleteOldCompletedTaskCaches();
}

View File

@ -1,5 +1,4 @@
using AntDesign;
using VideoAnalysisCore.AICore.GPT.Dto;
using VideoAnalysisCore.AICore.GPT.Dto;
using VideoAnalysisCore.Model.Enum;
namespace VideoAnalysisCore.Model.Dto

View File

@ -9,19 +9,19 @@ namespace VideoAnalysisCore.Model.Enum
{
public enum AttachmentsInfoType
{
[Description("默认")]
None = 0,
[Description("常规课程")]
RegularClasses = 1,
None = 0,
[Description("教研")]
TeachingResearch = 2,
TeachingResearch = 1,
[Description("PPT")]
PPT = 3,
PPT = 2,
[Description("复习")]
Review = 4,
Review = 3,
[Description("活动")]
Activities = 5,
Activities = 4,
[Description("班会")]
Meeting = 6,
Meeting = 5,
[Description("行为分析")]
Behavior = 6,
}
}

View File

@ -1,5 +1,4 @@
using AntDesign;
using SqlSugar;
using SqlSugar;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

View File

@ -1,5 +1,4 @@
using AntDesign;
using SqlSugar;
using SqlSugar;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

View File

@ -62,6 +62,8 @@
<PackageReference Include="FreeRedis" Version="1.3.2" />
<PackageReference Include="Downloader" Version="3.2.1" />
<PackageReference Include="Mapster" Version="7.4.1-pre01" />
<PackageReference Include="Microsoft.AspNetCore.Cors" Version="2.3.0" />
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.3.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Abstractions" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
@ -73,7 +75,6 @@
<PackageReference Include="Whisper.net" Version="1.5.0" />
<PackageReference Include="Whisper.net.Runtime" Version="1.5.0" />
<PackageReference Include="xFFmpeg.NET" Version="6.0.0" />
<PackageReference Include="AntDesign.ProLayout" Version="1.0.1" />
</ItemGroup>
<ItemGroup>