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 VideoAnalysisCore.Controllers.Dto; using VideoAnalysisCore.Model.Dto; using SqlSugar; using AlibabaCloud.SDK.Vod20170321; using VideoAnalysisCore.Model.蓝鲸智库; using AlibabaCloud.SDK.Vod20170321.Models; namespace VideoAnalysisCore.Controllers { /// /// 蓝鲸字库接口 /// [ApiController] [Route("LJZK/[action]")] public class LJZK_Controller : ControllerBase { private readonly IMapper mp; private readonly Repository nodesubscriptionDB; private readonly Repository videoTaskDB; private readonly Repository courseInfoDB; private readonly Repository videoKonwPointDB; private readonly Client vodClient; private readonly Repository videoTaskStageDB; private readonly Repository nodePackageInfoDB; private readonly Repository videoQuestionDB; private readonly Repository videoQuestionKonwDB; private readonly RedisManager redisManager; public LJZK_Controller(IMapper mp, Repository nodesubscriptionDB, Repository videoTaskDB = null, Repository videoKonwPointDB = null , Repository nodePackageInfoDB = null, Repository videoQuestionDB = null, Repository videoQuestionKonwDB = null, Repository courseInfoDB = null, RedisManager redisManager = null, Repository videoTaskStageDB = null, Client vodClient = null) { this.mp = mp; this.nodesubscriptionDB = nodesubscriptionDB; this.videoTaskDB = videoTaskDB; this.videoKonwPointDB = videoKonwPointDB; this.nodePackageInfoDB = nodePackageInfoDB; this.videoQuestionDB = videoQuestionDB; this.videoQuestionKonwDB = videoQuestionKonwDB; this.courseInfoDB = courseInfoDB; this.redisManager = redisManager; this.videoTaskStageDB = videoTaskStageDB; this.vodClient = vodClient; } /// /// 蓝鲸智库_文件包订阅 /// /// 请求体 /// [HttpPost(Name = "NodePackage")] public async Task NodePackage(NodePackageReq[] reqArr) { if (reqArr is null || reqArr.Count() == 0) return BadRequest("无效视频列表数据"); var videos = new List(reqArr.Count()); var nodePackages = new List(reqArr.Count()); var videoIdArr = videoTaskDB.AsQueryable().Select(v => v.TagId).Distinct().ToArray(); var courseArr = await courseInfoDB.AsQueryable().ToArrayAsync(); //系统可接收任务的学科 var subjectArr = new List { SubjectEnum.语文, SubjectEnum.数学, SubjectEnum.英语, SubjectEnum.物理, SubjectEnum.化学, SubjectEnum.生物, SubjectEnum.政治, SubjectEnum.历史, SubjectEnum.地理, }; var courseTypeArr = new List { AttachmentsInfoType.无, AttachmentsInfoType.新课, AttachmentsInfoType.复习 }; foreach (var sGroup in reqArr.GroupBy(s => s.ContentId)) { var s = sGroup.FirstOrDefault(s => s.VideoType == VideoType.摄像头); if (s is null) return BadRequest("无有效的老师授课视频"); //校验学科有效 if (!subjectArr.Contains(s.SubjectId)) continue; //无效的课程类型 if (!courseTypeArr.Contains(s.CourseType)) continue; var stageId = s.StageId.GetHashCode(); var subjectId = s.SubjectId.GetHashCode(); var course = courseArr.FirstOrDefault(x => stageId == x.Stage_Id && subjectId == x.Subject_Id); if (course == null) continue; var sPPT = sGroup.FirstOrDefault(s => s.VideoType == VideoType.PPT课件); var np = new NodePackageInfo() { VideoCode = s.VideoCode, MaterialId = s.MaterialId, AttachmentId = s.AttachmentId, Stage = s.StageId, CourseId = course.Id, SubjectType = s.SubjectId, VideoUrl = s.VideoUrl, CourseType = s.CourseType, CallBackUrl = s.CallBackUrl, CloudSchoolId = s.UserCenterCloudSchoolId, Area = s.Area, HostIP = s.HostIP, StageId = s.StageId, GradeId = s.GradeId, GradeYear = s.Trem == 0 ? null : s.Trem, GradeSemester = s.GradeSemester, TextBookVersionId = s.TextBookVersionId, }; nodePackages.Add(np); if (videoIdArr.Contains(s.VideoCode)) continue; var pptCode = sPPT != null ? sPPT.VideoCode : string.Empty; var pptUrl = sPPT != null ? sPPT.VideoUrl : string.Empty; videos.Add(new VideoTask() { Id = YitIdHelper.NextId(), ComeFrom = GetClientIpAddress(), ApiToken = "", EducationStage = s.StageId, CourseId = course.Id, Subject = s.SubjectId, TagId = s.VideoCode, MediaUrl = s.VideoUrl, PPTVideoCode = pptCode, PPTVideoUrl = pptUrl, VideoType = s.CourseType, CloudSchoolId = s.UserCenterCloudSchoolId, TextBookVersionId = s.TextBookVersionId, GradeSemester = s.GradeSemester, CourseLevel = s.CourseLevel, GradeId = s.GradeId, GradeYear = np.GradeYear, }); } 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(); redisManager.JoinQueue(RedisExpandKey.ChannelKey, ids); return Ok(); } 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地址"); } /// /// 获取任务类型 /// /// [HttpGet(Name = "TaskTypList")] public IActionResult TaskType() { Type type = typeof(TaskTypeEnum); return Ok(Enum.GetValues(type).Cast() .Select(s => new { Text = s.ToString(), Value = (int)s })); } /// /// 获取学科类型 /// /// [HttpGet(Name = "SubjectList")] public IActionResult Subject() { Type type = typeof(SubjectEnum); return Ok(Enum.GetValues(type).Cast() .Select(s => new { Text = s.ToString(), Value = (int)s })); } /// /// 获取视频知识点片段taskId/tagId二选一 /// /// 自定义id /// 自定义id /// [HttpGet(Name = "TaskKnowInfo")] public async Task TaskKnowInfo(string? tagId, string? taskId) { if (string.IsNullOrEmpty(tagId) && !string.IsNullOrEmpty(taskId)) tagId = taskId; if (string.IsNullOrEmpty(tagId)) return BadRequest(); var task = await videoTaskDB.AsQueryable() .Where(s => s.TagId == tagId || s.PPTVideoCode == 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("无有效任务分段"); var stageArr = await videoTaskStageDB.AsQueryable() .Where(s => s.VideoTaskId == task.Id) .ToArrayAsync(); var videoKnowDic = konwArr .GroupBy(s => s.StageId) .ToDictionary(s => s.Key); var videoKnows = stageArr .Select(s => new VideoKnowRes() { Content = s.Content, StartTime = s.StartTime, EndTime = s.EndTime, Theme = s.Theme, StageId = s.Id, KnowPoint = videoKnowDic.ContainsKey(s.Id) ? string.Join(',', videoKnowDic[s.Id].Select(x => x.KnowPoint)) : string.Empty }).ToArray(); var res = new TaskKnowRes() { TagId = task.TagId, Status = task.LastEnum, VideoTaskId = task.Id, KnowBlockArr = stageArr .Select(s => new TaskKnowBlock() { Id = s.Id, Content = s.Content, StartTime = s.StartTime, StageId = s.Id, EndTime = s.EndTime, Theme = s.Theme, Know = videoKnowDic.ContainsKey(s.Id) ? videoKnowDic[s.Id]?.Select(x => new TaskKnowInfo() { Id = x.Id, KnowPoint = x.KnowPoint, KnowPointId = x.KnowPointId, KnowWeight = x.KnowPointWeight ?? 0f, })?.ToArray() : null }).ToArray() }; if (task.VideoType == AttachmentsInfoType.复习) { var questionArr = await videoQuestionDB .AsQueryable().Where(s => s.VideoTaskId == task.Id) .Select() .ToArrayAsync(); var konwDic = (await videoQuestionKonwDB .AsQueryable().Where(s => s.VideoTaskId == task.Id) .ToArrayAsync()).GroupBy(s => s.VideoQuestionId) .ToDictionary(s => s.Key); foreach (var item in questionArr.Where(s => konwDic.ContainsKey(s.Id))) item.KonwArr = konwDic[item.Id].ToArray(); foreach (var item in res.KnowBlockArr) item.QuestionArr = questionArr .Where(s => s.StageId == item.StageId).ToArray(); } return Ok(res); } /// /// 查询 视频切片 /// /// /// [HttpPost(Name = "QueryVideoStage")] public async Task QueryVideoStage([FromBody] VideoKonwPointQueryReq req) { if (req is null) return BadRequest("参数不能为空"); var stageQuery = videoTaskStageDB.AsQueryable(); stageQuery = stageQuery.WhereIF(req.CloudSchoolId.HasValue, s => s.CloudSchoolId == req.CloudSchoolId); stageQuery = stageQuery.WhereIF(req.GradeYear.HasValue, s => s.GradeYear == req.GradeYear); stageQuery = stageQuery.WhereIF(req.CourseLevel.HasValue, s => s.CourseLevel == req.CourseLevel); stageQuery = stageQuery.WhereIF(req.GradeId.HasValue, s => s.GradeId == req.GradeId); stageQuery = stageQuery.WhereIF(req.GradeSemester.HasValue, s => s.GradeSemester == req.GradeSemester); stageQuery = stageQuery.WhereIF(req.TextBookVersionId.HasValue, s => s.TextBookVersionId == req.TextBookVersionId.Value); stageQuery = stageQuery.WhereIF(!string.IsNullOrWhiteSpace(req.Theme), s => s.Theme.Contains(req.Theme)); stageQuery = stageQuery.WhereIF(!string.IsNullOrWhiteSpace(req.Content), s => s.Content.Contains(req.Content)); //stageQuery = stageQuery.Where(s => s.Stage != StageEnum.课程引入); var pageIndex = req.PageIndex < 0 ? 0 : req.PageIndex; var pageSize = req.PageSize <= 0 ? 50 : req.PageSize > 100 ? 100 : req.PageSize; string[]? knowArr = null; if (req.KnowPointStrArr is not null && req.KnowPointStrArr.Length > 0) { knowArr = req.KnowPointStrArr.Where(s => !string.IsNullOrWhiteSpace(s)).Select(s => s.Trim()).Distinct().ToArray(); if (knowArr.Length > 0) { stageQuery = stageQuery.Where(s => SqlFunc.Subqueryable() .Where(k => k.StageId == s.Id && k.KnowPoint != null && knowArr.Contains(k.KnowPoint)) .Any()); } } RefAsync total = 0; var stagePageArr = await stageQuery.ToPageListAsync(pageIndex + 1, pageSize, total); if (stagePageArr is null || stagePageArr.Count == 0) return Ok(new VideoTaskStageQueryRes()); var taskIdArr = stagePageArr.Select(s => s.VideoTaskId).ToArray(); var kpQuery = videoKonwPointDB.AsQueryable() .Where(s => taskIdArr.Contains(s.VideoTaskId) && s.KnowPointId != null); //if (knowArr != null && knowArr.Length > 0) // kpQuery = kpQuery.Where(s => knowArr.Contains(s.KnowPoint)); var kpArr = await kpQuery .Select(s => new { s.StageId, s.KnowPoint }) .ToArrayAsync(); var kpDic = (kpArr ?? []) .GroupBy(s => s.StageId) .ToDictionary(s => s.Key, s => s.Select(x => x.KnowPoint!).Distinct().ToArray()); //var gDataKey = stagePageArr.GroupBy(s => s.VideoTaskId).Select(s => s.Key).Distinct(); //var videoInfoQRes = vodClient.GetVideoInfos(new GetVideoInfosRequest() //{ // VideoIds = string.Join(",", gDataKey) //}); //var videoInfoRes = videoInfoQRes.Body.VideoList.ToDictionary(s => s.VideoId, s => s.CoverURL); var data = stagePageArr.Select(s => new VideoTaskStageRes() { Id = s.Id, VideoTaskId = s.VideoTaskId, StartTime = s.StartTime, EndTime = s.EndTime, Theme = s.Theme, CloudSchoolId = s.CloudSchoolId, Stage = s.Stage.ToString(), CourseLevel = ((爱学蝶变层次Enum)(int)(s.CourseLevel ??CourselevelTypeEnum.无层次)).ToString(), GradeId = s.GradeId.ToString(), GradeYear = s.GradeYear?.ToString(), //PreviewUrl= videoInfoRes.ContainsKey(s.VideoTaskId.ToString())? videoInfoRes[] : KnowPoints = kpDic.ContainsKey(s.Id) ? kpDic[s.Id] : [] }).ToArray(); return Ok(new VideoTaskStageQueryRes() { Total = total, Data = data }); } /// /// 查询 视频切片 /// /// 视频id /// 视频地址 [HttpGet(Name = "GetVideoURL")] public async Task GetVideoURL(long videoTaskId) { if (videoTaskId == 0) return BadRequest("参数不能为空"); var task = await videoTaskDB.GetByIdAsync(videoTaskId); if (task is null) return BadRequest("参数无效"); if(!string.IsNullOrWhiteSpace(task.MediaUrl)) return Ok(task.MediaUrl); try { var videoInfo = await vodClient.GetPlayInfoAsync(new GetPlayInfoRequest() { VideoId = task.TagId, Formats = "mp4", OutputType = "cdn", AuthTimeout = 3600 * 24 * 12, }); if (videoInfo is null || videoInfo.StatusCode != 200 && !videoInfo.Body.PlayInfoList.PlayInfo.Any()) return BadRequest("获取存储的视频信息失败!"); return Ok(videoInfo.Body.PlayInfoList.PlayInfo.First().PlayURL); } catch (Exception ex) { return BadRequest("获取存储的视频信息失败!" + ex.Message); } } } }