完善 任务预览功能

This commit is contained in:
小肥羊 2025-01-10 18:25:28 +08:00
parent 59c8171ce8
commit eb45f0fd41
10 changed files with 139 additions and 90 deletions

View File

@ -18,7 +18,7 @@
<Routes @rendermode="InteractiveServer" /> <Routes @rendermode="InteractiveServer" />
<script type="text/javascript" src="@("https://unpkg.com/@antv/g2plot@2.4.17/dist/g2plot.min.js")"></script> <script type="text/javascript" src="@("https://unpkg.com/@antv/g2plot@2.4.17/dist/g2plot.min.js")"></script>
<script src="_content/AntDesign/js/ant-design-blazor.js"></script> <script src="_content/AntDesign/js/ant-design-blazor.js"></script>
<script src="_content/AntDesign.Charts/ant-design-charts-blazor.js"></script> @* <script src="_content/AntDesign.Charts/ant-design-charts-blazor.js"></script> *@
<script src="_framework/blazor.web.js"></script> <script src="_framework/blazor.web.js"></script>
</body> </body>

View File

@ -0,0 +1,15 @@
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.Security.Policy;
namespace Learn.VideoAnalysis.Components.Pages.Dto
{
public class TaskShowRoute : PageModel
{
public int ID;
public void OnGet(int id)
{
ID = id;
}
}
}

View File

@ -1,80 +1,72 @@
@page "/VideoTaskShow/{tid}" @page "/VideoTaskShow/{taskId:long}"
<div>
<input type="file" id="videoFile" accept="video/*">
<input type="file" id="subtitleFile" accept=".json">
<input type="file" id="segmentsFile" accept=".json">
</div>
<div id="video-container"> <div id="video-container">
<video id="videoPlayer" controls></video> @if (videoKnows != null)
{
<div id="segmentsContainer">
@for (int i = 0; i < videoKnows.Length; i++)
{
var item = videoKnows[i];
<button class="kBtn" onclick="spClick(@i,this)">@getF(item) @item.Theme </button>
}
</div>
}
<video id="videoPlayer" controls autoplay>
<source type="video/mp4" />
</video>
<div id="subtitleArea" class="subtitles"></div> <div id="subtitleArea" class="subtitles"></div>
</div> </div>
<div id="segmentsContainer"></div>
<script> <script>
const window.b = []
window.subtitles = []
var displayButton = []
var lastSegments = null;
function init() {
const videoPlayer = document.getElementById('videoPlayer'); const videoPlayer = document.getElementById('videoPlayer');
const subtitleArea = document.getElementById('subtitleArea'); const subtitleArea = document.getElementById('subtitleArea');
//视频时间变化时
let subtitles = @captionsArr
let segments = @videoKnows
let displayButton = []
let lastSegments = null;
window.onload(() => {
videoPlayer.src = @videoPath
})
videoPlayer.addEventListener('timeupdate', function () { videoPlayer.addEventListener('timeupdate', function () {
if (displayButton.length == 0) initKD()
const currentTime = videoPlayer.currentTime; const currentTime = videoPlayer.currentTime;
subtitleArea.textContent = ''; subtitleArea.textContent = '';
//字幕
subtitles.forEach(subtitle => { window.subtitles.forEach(subtitle => {
let textContent = subtitle.text
let textContent = subtitle.Text || subtitle.Content; if (currentTime >= subtitle.start
if (currentTime >= subtitle.Start && currentTime <= subtitle.end
&& currentTime <= subtitle.End
&& subtitleArea.textContent != textContent) { && subtitleArea.textContent != textContent) {
subtitleArea.textContent = textContent; subtitleArea.textContent = textContent;
} }
}); });
let segment = displayButton.find(s => currentTime >= s.开始秒 //时间片
&& currentTime <= s.结束秒) let segment = displayButton.find(s => currentTime >= s.startTime
&& currentTime <= s.endTime)
if (segment) { if (segment) {
segment.button.style.backgroundColor = "rgb(238, 200, 118)"; segment.button.style.backgroundColor = "rgb(238, 200, 118)";
if (lastSegments && lastSegments != segment) lastSegments.button.style.backgroundColor = "rgb(240, 249, 235)"; if (lastSegments && lastSegments != segment) lastSegments.button.style.backgroundColor = "rgb(240, 249, 235)";
lastSegments = segment lastSegments = segment
} }
}); });
function getF(segment) {
let sf = parseInt(segment.开始秒 / 60)
let sm = parseInt(segment.开始秒 % 60)
let ef = parseInt(segment.结束秒 / 60)
let em = parseInt(segment.结束秒 % 60)
return `${sf}:${sm} - ${ef}:${em}`
} }
function displaySegments() { function initKD() {
const segmentsContainer = document.getElementById('segmentsContainer'); let btns = document.getElementsByClassName("kBtn")
segmentsContainer.innerHTML = ''; if(btns.length == 0) return
segments.forEach(segment => { displayButton = window.b.map((s, i) => { return { ...s, button: btns[i] } })
const button = document.createElement('button'); }
displayButton.push(segment); //后端传递初始化数据
segment.button = button; function setDB(a, b,c) {
button.textContent = console.log("setDB", a, b,c)
`${getF(segment)} ${segment.主题}`; window.subtitles = a
button.addEventListener('click', () => { window.b = b
videoPlayer.currentTime = segment.开始秒; const videoPlayer = document.getElementById('videoPlayer');
videoPlayer.play(); videoPlayer.src=c
}); init()
segmentsContainer.appendChild(button); }
}); //点击时间片时
function spClick(i, button) {
videoPlayer.currentTime = displayButton[i].startTime;
} }
</script> </script>
@code {
}

View File

@ -5,6 +5,7 @@ using Learn.VideoAnalysis.Controllers.Dto;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web; using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.DataProtection.KeyManagement; using Microsoft.AspNetCore.DataProtection.KeyManagement;
using Microsoft.JSInterop;
using SqlSugar; using SqlSugar;
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -14,15 +15,21 @@ using VideoAnalysisCore.Common;
using VideoAnalysisCore.Enum; using VideoAnalysisCore.Enum;
using VideoAnalysisCore.Model; using VideoAnalysisCore.Model;
using VideoAnalysisCore.Model.Dto; using VideoAnalysisCore.Model.Dto;
using static System.Runtime.InteropServices.JavaScript.JSType;
namespace Learn.VideoAnalysis.Components.Pages namespace Learn.VideoAnalysis.Components.Pages
{ {
public partial class VideoTaskShow : ComponentBase public partial class VideoTaskShow : ComponentBase
{ {
/// <summary>
/// 任务id
/// </summary>
[Parameter]
public long? taskId { get; set; }
[Inject] private ConfirmService ComfirmService { get; set; } = default!; [Inject] private ConfirmService ComfirmService { get; set; } = default!;
[Inject] private IHttpContextAccessor HttpContext { get; set; } = default!; [Inject] private IHttpContextAccessor HttpContext { get; set; } = default!;
[Inject] private Repository<VideoTask> taskDB { get; set; } = default!; [Inject] private Repository<VideoTask> taskDB { get; set; } = default!;
[Inject] private IJSRuntime JSRuntime { get; set; } = default!;
private VideoTask nowTask { get; set; } = default!; private VideoTask nowTask { get; set; } = default!;
private string videoPath { get; set; } = default!; private string videoPath { get; set; } = default!;
@ -42,24 +49,37 @@ namespace Learn.VideoAnalysis.Components.Pages
/// <returns></returns> /// <returns></returns>
protected override async Task OnAfterRenderAsync(bool firstRender) protected override async Task OnAfterRenderAsync(bool firstRender)
{ {
if (firstRender)
{
}
}
public string getF(VideoKnowRes segment)
{
var sf = (int)((segment.StartTime ?? 0) / 60);
var sm = (int)((segment.StartTime ?? 0) % 60);
var ef = (int)((segment.EndTime ?? 0) / 60);
var em = (int)((segment.EndTime ?? 0) % 60);
return $"{sf}:{sm} - {ef}: {em}";
} }
/// <summary> /// <summary>
/// 初始化 /// 初始化
/// </summary> /// </summary>
protected override async void OnInitialized() protected override async void OnInitialized()
{ {
var routeData = HttpContext.HttpContext.GetRouteData(); if (this.taskId is null)
if (routeData is null)
return; return;
long taskId = (long)routeData.Values["id"]; long taskId = this.taskId.Value;
nowTask = await taskDB.GetFirstAsync(s => s.Id == taskId); nowTask = await taskDB.GetFirstAsync(s => s.Id == taskId);
if(nowTask is null) if(nowTask is null)
return; return;
captionsArr = RedisExpand.Redis.HMGet<SenseVoiceRes[]>(RedisExpandKey.Task(taskId), "Captions").FirstOrDefault(); captionsArr = RedisExpand.Redis.HMGet<SenseVoiceRes[]>(RedisExpandKey.Task(taskId), "Captions").FirstOrDefault();
videoKnows = RedisExpand.Redis.HMGet<VideoKnowRes[]>(RedisExpandKey.Task(taskId), "VideoKnows").FirstOrDefault(); videoKnows = RedisExpand.Redis.HMGet<VideoKnowRes[]>(RedisExpandKey.Task(taskId), "VideoKnows").FirstOrDefault();
videoPath = AppCommon.GetVideoPath(nowTask.Id.ToString()); videoPath = AppCommon.GetVideoPath(nowTask.Id.ToString());
await JSRuntime.InvokeVoidAsync("setDB", captionsArr,videoKnows, videoPath);
StateHasChanged();
} }
private async Task<bool> Comfirm(string message) private async Task<bool> Comfirm(string message)

View File

@ -6,27 +6,37 @@
#video-container { #video-container {
position: relative; position: relative;
width: 1600px; width: 1660px;
height: 850px; height: 850px;
float: left; float: left;
overflow-x: hidden;
} }
video { video {
width: 100%; width: 94%;
height: 100%; height: 85%;
} }
.subtitles { .subtitles {
position: absolute; position: absolute;
bottom: -40px; bottom: 200px;
width: 100%; width: 100%;
text-align: center; text-align: center;
color: white; color: white;
background-color: rgba(0, 0, 0, 0.7); background-color: rgba(0, 0, 0, 0.7);
font-size: 18px; font-size: 18px;
} }
#segmentsContainer:is(:hover) {
width: 400px;
right: 0px;
}
#segmentsContainer { #segmentsContainer {
transition:right 0.7s;
z-index:999;
overflow-x: hidden;
background-color: #e3e3e3c2;
position: absolute;
right: -180px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
width: 265px; width: 265px;

View File

@ -101,6 +101,7 @@ namespace Learn.VideoAnalysis
// app.UseExceptionHandler("/Login"); // app.UseExceptionHandler("/Login");
//} //}
app.UseStaticFiles();
app.UseStaticFiles(new StaticFileOptions app.UseStaticFiles(new StaticFileOptions
{ {

View File

@ -46,10 +46,10 @@ namespace VideoAnalysisCore.AICore.GPT.ChatGPT
foreach (var next in timeBases) foreach (var next in timeBases)
{ {
// 如果类型相同,则扩展时间段 // 如果类型相同,则扩展时间段
if (current. == next.) if (current.Theme == next.Theme)
{ {
current. = Math.Max(current..Value, next..Value); current.EndTime = Math.Max(current.EndTime.Value, next.EndTime.Value);
current. += next.; current.Content += next.Content;
} }
else else
{ {

View File

@ -15,12 +15,24 @@ namespace VideoAnalysisCore.AICore.GPT.Dto
/// <summary> /// <summary>
/// 问题解释 /// 问题解释
/// </summary> /// </summary>
public float? { get; set; } public float? StartTime { get; set; }
public float? { get; set; } public float? EndTime { get; set; }
public float? => ( ?? 0) - ??0; /// <summary>
public string? { get; set; } /// 持续时间
public string? { get; set; } /// </summary>
public string? { get; set; } public float? KeepTime => (EndTime ?? 0) - StartTime ?? 0;
/// <summary>
/// 主题
/// </summary>
public string? Theme { get; set; }
/// <summary>
/// 章节
/// </summary>
public string? Section { get; set; }
/// <summary>
/// 内容总结
/// </summary>
public string? Content { get; set; }
} }
public class FileNameInfo public class FileNameInfo

View File

@ -79,8 +79,7 @@ namespace VideoAnalysisCore.Common
/// </summary> /// </summary>
/// <param name="tid"></param> /// <param name="tid"></param>
/// <returns></returns> /// <returns></returns>
public static string GetVideoPath(string tid) => public static string GetVideoPath(string tid) => $"./video/{tid}/{tid}.mp4";
Path.Combine(TaskCachedFile, tid, tid + ".mp4");
} }
/// <summary> /// <summary>

View File

@ -167,7 +167,7 @@ namespace VideoAnalysisCore.Common
var taskData = await DbScoped.SugarScope.Queryable<VideoTask>() var taskData = await DbScoped.SugarScope.Queryable<VideoTask>()
.FirstAsync(s => s.Id == tId); .FirstAsync(s => s.Id == tId);
taskData.ChatAnalysis = gptRes; taskData.ChatAnalysis = gptRes;
taskData.ChatAnalysisScore = gptRes.Assessment.Merit?.Sum(s => s.Score) ?? 0; taskData.ChatAnalysisScore = gptRes?.Assessment?.Merit?.Sum(s => s.Score) ?? 0;
taskData.ErrorMessage = string.Empty; taskData.ErrorMessage = string.Empty;
taskData.LastEnum = RedisChannelEnum.EndTask; taskData.LastEnum = RedisChannelEnum.EndTask;
await DbScoped.SugarScope.Updateable(taskData) await DbScoped.SugarScope.Updateable(taskData)